[NPM] General translation logic for linux and windows (#1055)
* Create generic translation struct and start using it networkPolicyController * Update ipsm to get more information from NPMCache * Working on translateIngress part and its UTs * Done functions of Translate ingress rule (need to add UTs to test its functions and clean up codes) * Use function for repeated codes * Cleanup UTs * Remove all unused codes in this PR except for ingress rules * Create functions to make codes concise and reorganize ipsets for better readability * Remove duplicated data for targetPod information in every ACL * Move translation logics to /pkg/controlplane/translation dir * Remove redundant codes and resolved some of lint errors * Resolve lint errors and remove unused codes in parseSelector and its UTs * Use unique id for acl policy among network policies and add UTs for port rules * Addresses some comments (will resolve more later) * Complete namespaceSelector UTs and correct some logics for handling namespaceSelector * Use consistent variables and variable for flexibility in UTs * Add more UTs for allowAll and defaultDrop rules and clean-up codes * Remove unused codes * Resolve lint errors * Clean-up and reorganize codes * Revert "Update ipsm to get more information from NPMCache" This reverts commit 477bbaf43d56a6535f5cc035dfe15d5b6035647a. * Address comments * Resolve part of lint errors * Add comments for todo things in next PR * Delete unused file and clean-up code * Fix Uts * Remove unnecessary code
This commit is contained in:
Родитель
66453dd20b
Коммит
8434e139d1
|
@ -0,0 +1,240 @@
|
|||
package translation
|
||||
|
||||
import (
|
||||
"github.com/Azure/azure-container-networking/log"
|
||||
"github.com/Azure/azure-container-networking/npm/util"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
// ParseLabel takes a Azure-NPM processed label then returns if it's referring to complement set,
|
||||
// and if so, returns the original set as well.
|
||||
func ParseLabel(label string) (string, bool) {
|
||||
// The input label is guaranteed to have a non-zero length validated by k8s.
|
||||
// For label definition, see below parseSelector() function.
|
||||
if label[0:1] == util.IptablesNotFlag {
|
||||
return label[1:], true
|
||||
}
|
||||
return label, false
|
||||
}
|
||||
|
||||
// GetOperatorAndLabel returns the operator associated with the label and the label without operator.
|
||||
func GetOperatorAndLabel(labelWithOp string) (op, label string) {
|
||||
// TODO(jungukcho): check whether this is possible
|
||||
if labelWithOp == "" {
|
||||
return op, label
|
||||
}
|
||||
|
||||
// in case "!"" Operaror do not exist
|
||||
if string(labelWithOp[0]) != util.IptablesNotFlag {
|
||||
label = labelWithOp
|
||||
return op, label
|
||||
}
|
||||
|
||||
// in case "!"" Operaror exists
|
||||
op, label = util.IptablesNotFlag, labelWithOp[1:]
|
||||
return op, label
|
||||
}
|
||||
|
||||
// GetOperatorsAndLabels returns the operators along with the associated labels.
|
||||
func GetOperatorsAndLabels(labelsWithOps []string) (ops, labelsWithoutOps []string) {
|
||||
ops = make([]string, len(labelsWithOps))
|
||||
labelsWithoutOps = make([]string, len(labelsWithOps))
|
||||
|
||||
for i, labelWithOp := range labelsWithOps {
|
||||
op, labelWithoutOp := GetOperatorAndLabel(labelWithOp)
|
||||
ops[i] = op
|
||||
labelsWithoutOps[i] = labelWithoutOp
|
||||
}
|
||||
|
||||
return ops, labelsWithoutOps
|
||||
}
|
||||
|
||||
// getSetNameForMultiValueSelector takes in label with multiple values without operator
|
||||
// and returns a new 2nd level ipset name
|
||||
func getSetNameForMultiValueSelector(key string, vals []string) string {
|
||||
newIPSet := key
|
||||
for _, val := range vals {
|
||||
newIPSet = util.GetIpSetFromLabelKV(newIPSet, val)
|
||||
}
|
||||
return newIPSet
|
||||
}
|
||||
|
||||
// FlattenNameSpaceSelector will help flatten multiple NameSpace selector match Expressions values
|
||||
// into multiple label selectors helping with the OR condition.
|
||||
func FlattenNameSpaceSelector(nsSelector *metav1.LabelSelector) []metav1.LabelSelector {
|
||||
/*
|
||||
This function helps to create multiple labelSelectors when given a single multivalue nsSelector
|
||||
Take below example: this nsSelector has 2 values in a matchSelector.
|
||||
- namespaceSelector:
|
||||
matchExpressions:
|
||||
- key: ns
|
||||
operator: NotIn
|
||||
values:
|
||||
- netpol-x
|
||||
- netpol-y
|
||||
|
||||
goal is to convert this single nsSelector into multiple nsSelectors to preserve OR condition
|
||||
between multiple values of the matchExpr i.e. this function will return
|
||||
|
||||
- namespaceSelector:
|
||||
matchExpressions:
|
||||
- key: ns
|
||||
operator: NotIn
|
||||
values:
|
||||
- netpol-x
|
||||
- namespaceSelector:
|
||||
matchExpressions:
|
||||
- key: ns
|
||||
operator: NotIn
|
||||
values:
|
||||
- netpol-y
|
||||
|
||||
then, translate policy will replicate each of these nsSelectors to add two different rules in iptables,
|
||||
resulting in OR condition between the values.
|
||||
|
||||
Check TestFlattenNameSpaceSelector 2nd subcase for complex scenario
|
||||
*/
|
||||
|
||||
// To avoid any additional length checks, just return a slice of labelSelectors
|
||||
// with original nsSelector
|
||||
if nsSelector == nil {
|
||||
return []metav1.LabelSelector{}
|
||||
}
|
||||
|
||||
if len(nsSelector.MatchExpressions) == 0 {
|
||||
return []metav1.LabelSelector{*nsSelector}
|
||||
}
|
||||
|
||||
// create a baseSelector which needs to be same across all
|
||||
// new labelSelectors
|
||||
baseSelector := &metav1.LabelSelector{
|
||||
MatchLabels: nsSelector.MatchLabels,
|
||||
MatchExpressions: []metav1.LabelSelectorRequirement{},
|
||||
}
|
||||
|
||||
multiValuePresent := false
|
||||
multiValueMatchExprs := []metav1.LabelSelectorRequirement{}
|
||||
for _, req := range nsSelector.MatchExpressions {
|
||||
// Only In and NotIn operators of matchExprs have multiple values
|
||||
// NPM will ignore single value matchExprs of these operators.
|
||||
// for multiple values, it will create a slice of them to be used for Zipping with baseSelector
|
||||
// to create multiple nsSelectors to preserve OR condition across all labels and expressions
|
||||
switch {
|
||||
case (req.Operator == metav1.LabelSelectorOpIn) || (req.Operator == metav1.LabelSelectorOpNotIn):
|
||||
if len(req.Values) == 1 {
|
||||
// for length 1, add the matchExpr to baseSelector
|
||||
baseSelector.MatchExpressions = append(baseSelector.MatchExpressions, req)
|
||||
} else {
|
||||
multiValuePresent = true
|
||||
multiValueMatchExprs = append(multiValueMatchExprs, req)
|
||||
}
|
||||
case (req.Operator == metav1.LabelSelectorOpExists) || (req.Operator == metav1.LabelSelectorOpDoesNotExist):
|
||||
// since Exists and NotExists do not contain any values, NPM can safely add them to the baseSelector
|
||||
baseSelector.MatchExpressions = append(baseSelector.MatchExpressions, req)
|
||||
default:
|
||||
log.Errorf("Invalid operator [%s] for selector [%v] requirement", req.Operator, *nsSelector)
|
||||
}
|
||||
}
|
||||
|
||||
// If there are no multiValue NS selector match expressions
|
||||
// return the original NsSelector
|
||||
if !multiValuePresent {
|
||||
return []metav1.LabelSelector{*nsSelector}
|
||||
}
|
||||
|
||||
// Now use the baseSelector and loop over multiValueMatchExprs to create all
|
||||
// combinations of values
|
||||
flatNsSelectors := []metav1.LabelSelector{
|
||||
*baseSelector.DeepCopy(),
|
||||
}
|
||||
for _, req := range multiValueMatchExprs {
|
||||
flatNsSelectors = zipMatchExprs(flatNsSelectors, req)
|
||||
}
|
||||
|
||||
return flatNsSelectors
|
||||
}
|
||||
|
||||
// zipMatchExprs helps with zipping a given matchExpr with given baseLabelSelectors
|
||||
// this func will loop over each baseSelector in the slice,
|
||||
// deepCopies each baseSelector, combines with given matchExpr by looping over each value
|
||||
// and creating a new LabelSelector with given baseSelector and value matchExpr
|
||||
// then returns a new slice of these zipped LabelSelectors
|
||||
func zipMatchExprs(baseSelectors []metav1.LabelSelector, matchExpr metav1.LabelSelectorRequirement) []metav1.LabelSelector {
|
||||
zippedLabelSelectors := []metav1.LabelSelector{}
|
||||
for _, selector := range baseSelectors {
|
||||
for _, value := range matchExpr.Values {
|
||||
tempBaseSelector := selector.DeepCopy()
|
||||
tempBaseSelector.MatchExpressions = append(
|
||||
tempBaseSelector.MatchExpressions,
|
||||
metav1.LabelSelectorRequirement{
|
||||
Key: matchExpr.Key,
|
||||
Operator: matchExpr.Operator,
|
||||
Values: []string{value},
|
||||
},
|
||||
)
|
||||
zippedLabelSelectors = append(zippedLabelSelectors, *tempBaseSelector)
|
||||
|
||||
}
|
||||
}
|
||||
return zippedLabelSelectors
|
||||
}
|
||||
|
||||
// parseSelector takes a LabelSelector and returns a slice of processed labels, Lists with members as values.
|
||||
// this function returns a slice of all the label ipsets excluding multivalue matchExprs
|
||||
// and a map of labelKeys and labelIpsetname for multivalue match exprs
|
||||
// higher level functions will need to compute what sets or ipsets should be
|
||||
// used from this map
|
||||
func parseSelector(selector *metav1.LabelSelector) (labels []string, vals map[string][]string) {
|
||||
// TODO(jungukcho): check return values
|
||||
// labels []string and []string{}
|
||||
if selector == nil {
|
||||
return labels, vals
|
||||
}
|
||||
|
||||
labels = []string{}
|
||||
vals = make(map[string][]string)
|
||||
if len(selector.MatchLabels) == 0 && len(selector.MatchExpressions) == 0 {
|
||||
labels = append(labels, "")
|
||||
return labels, vals
|
||||
}
|
||||
|
||||
sortedKeys, sortedVals := util.SortMap(&selector.MatchLabels)
|
||||
for i := range sortedKeys {
|
||||
labels = append(labels, sortedKeys[i]+":"+sortedVals[i])
|
||||
}
|
||||
|
||||
for _, req := range selector.MatchExpressions {
|
||||
var k string
|
||||
switch op := req.Operator; op {
|
||||
case metav1.LabelSelectorOpIn:
|
||||
k = req.Key
|
||||
if len(req.Values) == 1 {
|
||||
labels = append(labels, k+":"+req.Values[0])
|
||||
} else {
|
||||
// We are not adding the k:v to labels for multiple values, because, labels are used
|
||||
// to construct partial IptEntries and if these below labels are added then we are inducing
|
||||
// AND condition on values of a match expression instead of OR
|
||||
vals[k] = append(vals[k], req.Values...)
|
||||
}
|
||||
case metav1.LabelSelectorOpNotIn:
|
||||
k = util.IptablesNotFlag + req.Key
|
||||
if len(req.Values) == 1 {
|
||||
labels = append(labels, k+":"+req.Values[0])
|
||||
} else {
|
||||
vals[k] = append(vals[k], req.Values...)
|
||||
}
|
||||
// Exists matches pods with req.Key as key
|
||||
case metav1.LabelSelectorOpExists:
|
||||
k = req.Key
|
||||
labels = append(labels, k)
|
||||
// DoesNotExist matches pods without req.Key as key
|
||||
case metav1.LabelSelectorOpDoesNotExist:
|
||||
k = util.IptablesNotFlag + req.Key
|
||||
labels = append(labels, k)
|
||||
default:
|
||||
log.Errorf("Invalid operator [%s] for selector [%v] requirement", op, *selector)
|
||||
}
|
||||
}
|
||||
|
||||
return labels, vals
|
||||
}
|
|
@ -0,0 +1,763 @@
|
|||
package translation
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/Azure/azure-container-networking/npm/util"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
func TestParseLabel(t *testing.T) {
|
||||
label, isComplementSet := ParseLabel("test:frontend")
|
||||
expectedLabel := "test:frontend"
|
||||
if isComplementSet || label != expectedLabel {
|
||||
t.Errorf("TestParseLabel failed @ label %s", label)
|
||||
}
|
||||
|
||||
label, isComplementSet = ParseLabel("!test:frontend")
|
||||
expectedLabel = "test:frontend"
|
||||
if !isComplementSet || label != expectedLabel {
|
||||
t.Errorf("TestParseLabel failed @ label %s", label)
|
||||
}
|
||||
|
||||
label, isComplementSet = ParseLabel("test")
|
||||
expectedLabel = "test"
|
||||
if isComplementSet || label != expectedLabel {
|
||||
t.Errorf("TestParseLabel failed @ label %s", label)
|
||||
}
|
||||
|
||||
label, isComplementSet = ParseLabel("!test")
|
||||
expectedLabel = "test"
|
||||
if !isComplementSet || label != expectedLabel {
|
||||
t.Errorf("TestParseLabel failed @ label %s", label)
|
||||
}
|
||||
|
||||
label, isComplementSet = ParseLabel("!!test")
|
||||
expectedLabel = "!test"
|
||||
if !isComplementSet || label != expectedLabel {
|
||||
t.Errorf("TestParseLabel failed @ label %s", label)
|
||||
}
|
||||
|
||||
label, isComplementSet = ParseLabel("test:!frontend")
|
||||
expectedLabel = "test:!frontend"
|
||||
if isComplementSet || label != expectedLabel {
|
||||
t.Errorf("TestParseLabel failed @ label %s", label)
|
||||
}
|
||||
|
||||
label, isComplementSet = ParseLabel("!test:!frontend")
|
||||
expectedLabel = "test:!frontend"
|
||||
if !isComplementSet || label != expectedLabel {
|
||||
t.Errorf("TestParseLabel failed @ label %s", label)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetOperatorAndLabel(t *testing.T) {
|
||||
testLabels := []string{
|
||||
"a",
|
||||
"k:v",
|
||||
"",
|
||||
"!a:b",
|
||||
"!a",
|
||||
}
|
||||
|
||||
resultOperators, resultLabels := []string{}, []string{}
|
||||
for _, testLabel := range testLabels {
|
||||
resultOperator, resultLabel := GetOperatorAndLabel(testLabel)
|
||||
resultOperators = append(resultOperators, resultOperator)
|
||||
resultLabels = append(resultLabels, resultLabel)
|
||||
}
|
||||
|
||||
expectedOperators := []string{
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
util.IptablesNotFlag,
|
||||
util.IptablesNotFlag,
|
||||
}
|
||||
|
||||
expectedLabels := []string{
|
||||
"a",
|
||||
"k:v",
|
||||
"",
|
||||
"a:b",
|
||||
"a",
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(resultOperators, expectedOperators) {
|
||||
t.Errorf("TestGetOperatorAndLabel failed @ operator comparison")
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(resultLabels, expectedLabels) {
|
||||
t.Errorf("TestGetOperatorAndLabel failed @ label comparison")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetOperatorsAndLabels(t *testing.T) {
|
||||
testLabels := []string{
|
||||
"k:v",
|
||||
"",
|
||||
"!a:b",
|
||||
}
|
||||
|
||||
resultOps, resultLabels := GetOperatorsAndLabels(testLabels)
|
||||
expectedOps := []string{
|
||||
"",
|
||||
"",
|
||||
"!",
|
||||
}
|
||||
expectedLabels := []string{
|
||||
"k:v",
|
||||
"",
|
||||
"a:b",
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(resultOps, expectedOps) {
|
||||
t.Errorf("TestGetOperatorsAndLabels failed @ op comparison")
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(resultLabels, expectedLabels) {
|
||||
t.Errorf("TestGetOperatorsAndLabels failed @ label comparison")
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(jungukcho): check UT results.
|
||||
func TestParseSelector(t *testing.T) {
|
||||
var selector, expectedSelector *metav1.LabelSelector
|
||||
selector, expectedSelector = nil, nil
|
||||
labels, vals := parseSelector(selector)
|
||||
expectedLabels, expectedVals := []string{}, make(map[string][]string)
|
||||
|
||||
if len(labels) != len(expectedLabels) {
|
||||
t.Errorf("TestparseSelector failed @ labels length comparison")
|
||||
}
|
||||
|
||||
if len(vals) != len(expectedVals) {
|
||||
t.Errorf("TestparseSelector failed @ vals length comparison")
|
||||
}
|
||||
|
||||
if selector != expectedSelector {
|
||||
t.Errorf("TestparseSelector failed @ vals length comparison")
|
||||
}
|
||||
|
||||
selector = &metav1.LabelSelector{}
|
||||
labels, vals = parseSelector(selector)
|
||||
expectedLabels = []string{""}
|
||||
if len(labels) != len(expectedLabels) {
|
||||
t.Errorf("TestparseSelector failed @ labels length comparison")
|
||||
}
|
||||
|
||||
if len(vals) != len(expectedVals) {
|
||||
t.Errorf("TestparseSelector failed @ vals length comparison")
|
||||
}
|
||||
|
||||
selector = &metav1.LabelSelector{
|
||||
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||
{
|
||||
Key: "testIn",
|
||||
Operator: metav1.LabelSelectorOpIn,
|
||||
Values: []string{
|
||||
"frontend",
|
||||
"backend",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
labels, vals = parseSelector(selector)
|
||||
expectedLabels = []string{}
|
||||
expectedVals = map[string][]string{
|
||||
"testIn": {
|
||||
"frontend",
|
||||
"backend",
|
||||
},
|
||||
}
|
||||
|
||||
if len(labels) != len(expectedLabels) {
|
||||
t.Errorf("TestparseSelector failed @ labels length comparison")
|
||||
}
|
||||
|
||||
if len(vals) != len(expectedVals) {
|
||||
t.Errorf("TestparseSelector failed @ vals length comparison")
|
||||
}
|
||||
|
||||
if len(labels) != 0 {
|
||||
t.Errorf("TestparseSelector failed @ label comparison")
|
||||
}
|
||||
if !reflect.DeepEqual(vals, expectedVals) {
|
||||
t.Errorf("TestparseSelector failed @ value comparison")
|
||||
}
|
||||
|
||||
notIn := metav1.LabelSelectorRequirement{
|
||||
Key: "testNotIn",
|
||||
Operator: metav1.LabelSelectorOpNotIn,
|
||||
Values: []string{
|
||||
"frontend",
|
||||
"backend",
|
||||
},
|
||||
}
|
||||
|
||||
me := &selector.MatchExpressions
|
||||
*me = append(*me, notIn)
|
||||
|
||||
labels, vals = parseSelector(selector)
|
||||
addedLabels := []string{}
|
||||
addedVals := map[string][]string{
|
||||
"!testNotIn": {
|
||||
"frontend",
|
||||
"backend",
|
||||
},
|
||||
}
|
||||
|
||||
expectedLabels = append(expectedLabels, addedLabels...)
|
||||
for k, v := range addedVals {
|
||||
expectedVals[k] = append(expectedVals[k], v...)
|
||||
}
|
||||
|
||||
if len(labels) != len(expectedLabels) {
|
||||
t.Errorf("TestparseSelector failed @ labels length comparison")
|
||||
}
|
||||
|
||||
if len(vals) != len(expectedVals) {
|
||||
t.Errorf("TestparseSelector failed @ vals length comparison")
|
||||
}
|
||||
|
||||
if len(labels) != 0 {
|
||||
t.Errorf("TestparseSelector failed @ label comparison")
|
||||
}
|
||||
if !reflect.DeepEqual(vals, expectedVals) {
|
||||
t.Errorf("TestparseSelector failed @ value comparison")
|
||||
}
|
||||
|
||||
exists := metav1.LabelSelectorRequirement{
|
||||
Key: "testExists",
|
||||
Operator: metav1.LabelSelectorOpExists,
|
||||
Values: []string{},
|
||||
}
|
||||
|
||||
*me = append(*me, exists)
|
||||
|
||||
labels, vals = parseSelector(selector)
|
||||
addedLabels = []string{
|
||||
"testExists",
|
||||
}
|
||||
addedVals = map[string][]string{}
|
||||
expectedLabels = append(expectedLabels, addedLabels...)
|
||||
for k, v := range addedVals {
|
||||
expectedVals[k] = append(expectedVals[k], v...)
|
||||
}
|
||||
|
||||
if len(labels) != len(expectedLabels) {
|
||||
t.Errorf("TestparseSelector failed @ labels length comparison")
|
||||
}
|
||||
|
||||
if len(vals) != len(expectedVals) {
|
||||
t.Errorf("TestparseSelector failed @ vals length comparison")
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(labels, expectedLabels) {
|
||||
t.Errorf("TestparseSelector failed @ label comparison")
|
||||
}
|
||||
if !reflect.DeepEqual(vals, expectedVals) {
|
||||
t.Errorf("TestparseSelector failed @ value comparison")
|
||||
}
|
||||
|
||||
doesNotExist := metav1.LabelSelectorRequirement{
|
||||
Key: "testDoesNotExist",
|
||||
Operator: metav1.LabelSelectorOpDoesNotExist,
|
||||
Values: []string{},
|
||||
}
|
||||
|
||||
*me = append(*me, doesNotExist)
|
||||
|
||||
labels, vals = parseSelector(selector)
|
||||
addedLabels = []string{
|
||||
"!testDoesNotExist",
|
||||
}
|
||||
addedVals = map[string][]string{}
|
||||
expectedLabels = append(expectedLabels, addedLabels...)
|
||||
for k, v := range addedVals {
|
||||
expectedVals[k] = append(expectedVals[k], v...)
|
||||
}
|
||||
|
||||
if len(labels) != len(expectedLabels) {
|
||||
t.Errorf("TestparseSelector failed @ labels length comparison")
|
||||
}
|
||||
|
||||
if len(vals) != len(expectedVals) {
|
||||
t.Errorf("TestparseSelector failed @ vals length comparison")
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(labels, expectedLabels) {
|
||||
t.Errorf("TestparseSelector failed @ label comparison")
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(vals, expectedVals) {
|
||||
t.Errorf("TestparseSelector failed @ value comparison")
|
||||
}
|
||||
}
|
||||
|
||||
func TestFlattenNameSpaceSelectorCases(t *testing.T) {
|
||||
firstSelector := &metav1.LabelSelector{}
|
||||
|
||||
testSelectors := FlattenNameSpaceSelector(firstSelector)
|
||||
if len(testSelectors) != 1 {
|
||||
t.Errorf("TestFlattenNameSpaceSelectorCases failed @ 1st selector length check %+v", testSelectors)
|
||||
}
|
||||
|
||||
var secondSelector *metav1.LabelSelector
|
||||
|
||||
testSelectors = FlattenNameSpaceSelector(secondSelector)
|
||||
if len(testSelectors) > 0 {
|
||||
t.Errorf("TestFlattenNameSpaceSelectorCases failed @ 1st selector length check %+v", testSelectors)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFlattenNameSpaceSelector(t *testing.T) {
|
||||
commonMatchLabel := map[string]string{
|
||||
"c": "d",
|
||||
"a": "b",
|
||||
}
|
||||
|
||||
firstSelector := &metav1.LabelSelector{
|
||||
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||
{
|
||||
Key: "testIn",
|
||||
Operator: metav1.LabelSelectorOpIn,
|
||||
Values: []string{
|
||||
"backend",
|
||||
},
|
||||
},
|
||||
{
|
||||
Key: "pod",
|
||||
Operator: metav1.LabelSelectorOpIn,
|
||||
Values: []string{
|
||||
"a",
|
||||
},
|
||||
},
|
||||
{
|
||||
Key: "testExists",
|
||||
Operator: metav1.LabelSelectorOpExists,
|
||||
Values: []string{},
|
||||
},
|
||||
{
|
||||
Key: "ns",
|
||||
Operator: metav1.LabelSelectorOpIn,
|
||||
Values: []string{
|
||||
"t",
|
||||
},
|
||||
},
|
||||
},
|
||||
MatchLabels: commonMatchLabel,
|
||||
}
|
||||
|
||||
testSelectors := FlattenNameSpaceSelector(firstSelector)
|
||||
if len(testSelectors) != 1 {
|
||||
t.Errorf("TestFlattenNameSpaceSelector failed @ 1st selector length check %+v", testSelectors)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(testSelectors[0], *firstSelector) {
|
||||
t.Errorf("TestFlattenNameSpaceSelector failed @ 1st selector deepEqual check.\n Expected: %+v \n Actual: %+v", *firstSelector, testSelectors[0])
|
||||
}
|
||||
|
||||
secondSelector := &metav1.LabelSelector{
|
||||
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||
{
|
||||
Key: "testIn",
|
||||
Operator: metav1.LabelSelectorOpIn,
|
||||
Values: []string{
|
||||
"backend",
|
||||
"frontend",
|
||||
},
|
||||
},
|
||||
{
|
||||
Key: "pod",
|
||||
Operator: metav1.LabelSelectorOpIn,
|
||||
Values: []string{
|
||||
"a",
|
||||
"b",
|
||||
},
|
||||
},
|
||||
{
|
||||
Key: "testExists",
|
||||
Operator: metav1.LabelSelectorOpExists,
|
||||
Values: []string{},
|
||||
},
|
||||
{
|
||||
Key: "ns",
|
||||
Operator: metav1.LabelSelectorOpIn,
|
||||
Values: []string{
|
||||
"t",
|
||||
"y",
|
||||
},
|
||||
},
|
||||
},
|
||||
MatchLabels: commonMatchLabel,
|
||||
}
|
||||
|
||||
testSelectors = FlattenNameSpaceSelector(secondSelector)
|
||||
if len(testSelectors) != 8 {
|
||||
t.Errorf("TestFlattenNameSpaceSelector failed @ 2nd selector length check %+v", testSelectors)
|
||||
}
|
||||
|
||||
expectedSelectors := []metav1.LabelSelector{
|
||||
{
|
||||
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||
{
|
||||
Key: "testExists",
|
||||
Operator: metav1.LabelSelectorOpExists,
|
||||
Values: []string{},
|
||||
},
|
||||
{
|
||||
Key: "testIn",
|
||||
Operator: metav1.LabelSelectorOpIn,
|
||||
Values: []string{
|
||||
"backend",
|
||||
},
|
||||
},
|
||||
{
|
||||
Key: "pod",
|
||||
Operator: metav1.LabelSelectorOpIn,
|
||||
Values: []string{
|
||||
"a",
|
||||
},
|
||||
},
|
||||
{
|
||||
Key: "ns",
|
||||
Operator: metav1.LabelSelectorOpIn,
|
||||
Values: []string{
|
||||
"t",
|
||||
},
|
||||
},
|
||||
},
|
||||
MatchLabels: commonMatchLabel,
|
||||
},
|
||||
{
|
||||
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||
{
|
||||
Key: "testExists",
|
||||
Operator: metav1.LabelSelectorOpExists,
|
||||
Values: []string{},
|
||||
},
|
||||
{
|
||||
Key: "testIn",
|
||||
Operator: metav1.LabelSelectorOpIn,
|
||||
Values: []string{
|
||||
"backend",
|
||||
},
|
||||
},
|
||||
{
|
||||
Key: "pod",
|
||||
Operator: metav1.LabelSelectorOpIn,
|
||||
Values: []string{
|
||||
"a",
|
||||
},
|
||||
},
|
||||
{
|
||||
Key: "ns",
|
||||
Operator: metav1.LabelSelectorOpIn,
|
||||
Values: []string{
|
||||
"y",
|
||||
},
|
||||
},
|
||||
},
|
||||
MatchLabels: commonMatchLabel,
|
||||
},
|
||||
{
|
||||
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||
{
|
||||
Key: "testExists",
|
||||
Operator: metav1.LabelSelectorOpExists,
|
||||
Values: []string{},
|
||||
},
|
||||
{
|
||||
Key: "testIn",
|
||||
Operator: metav1.LabelSelectorOpIn,
|
||||
Values: []string{
|
||||
"backend",
|
||||
},
|
||||
},
|
||||
{
|
||||
Key: "pod",
|
||||
Operator: metav1.LabelSelectorOpIn,
|
||||
Values: []string{
|
||||
"b",
|
||||
},
|
||||
},
|
||||
{
|
||||
Key: "ns",
|
||||
Operator: metav1.LabelSelectorOpIn,
|
||||
Values: []string{
|
||||
"t",
|
||||
},
|
||||
},
|
||||
},
|
||||
MatchLabels: commonMatchLabel,
|
||||
},
|
||||
{
|
||||
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||
{
|
||||
Key: "testExists",
|
||||
Operator: metav1.LabelSelectorOpExists,
|
||||
Values: []string{},
|
||||
},
|
||||
{
|
||||
Key: "testIn",
|
||||
Operator: metav1.LabelSelectorOpIn,
|
||||
Values: []string{
|
||||
"backend",
|
||||
},
|
||||
},
|
||||
{
|
||||
Key: "pod",
|
||||
Operator: metav1.LabelSelectorOpIn,
|
||||
Values: []string{
|
||||
"b",
|
||||
},
|
||||
},
|
||||
{
|
||||
Key: "ns",
|
||||
Operator: metav1.LabelSelectorOpIn,
|
||||
Values: []string{
|
||||
"y",
|
||||
},
|
||||
},
|
||||
},
|
||||
MatchLabels: commonMatchLabel,
|
||||
},
|
||||
{
|
||||
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||
{
|
||||
Key: "testExists",
|
||||
Operator: metav1.LabelSelectorOpExists,
|
||||
Values: []string{},
|
||||
},
|
||||
{
|
||||
Key: "testIn",
|
||||
Operator: metav1.LabelSelectorOpIn,
|
||||
Values: []string{
|
||||
"frontend",
|
||||
},
|
||||
},
|
||||
{
|
||||
Key: "pod",
|
||||
Operator: metav1.LabelSelectorOpIn,
|
||||
Values: []string{
|
||||
"a",
|
||||
},
|
||||
},
|
||||
{
|
||||
Key: "ns",
|
||||
Operator: metav1.LabelSelectorOpIn,
|
||||
Values: []string{
|
||||
"t",
|
||||
},
|
||||
},
|
||||
},
|
||||
MatchLabels: commonMatchLabel,
|
||||
},
|
||||
{
|
||||
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||
{
|
||||
Key: "testExists",
|
||||
Operator: metav1.LabelSelectorOpExists,
|
||||
Values: []string{},
|
||||
},
|
||||
{
|
||||
Key: "testIn",
|
||||
Operator: metav1.LabelSelectorOpIn,
|
||||
Values: []string{
|
||||
"frontend",
|
||||
},
|
||||
},
|
||||
{
|
||||
Key: "pod",
|
||||
Operator: metav1.LabelSelectorOpIn,
|
||||
Values: []string{
|
||||
"a",
|
||||
},
|
||||
},
|
||||
{
|
||||
Key: "ns",
|
||||
Operator: metav1.LabelSelectorOpIn,
|
||||
Values: []string{
|
||||
"y",
|
||||
},
|
||||
},
|
||||
},
|
||||
MatchLabels: commonMatchLabel,
|
||||
},
|
||||
{
|
||||
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||
{
|
||||
Key: "testExists",
|
||||
Operator: metav1.LabelSelectorOpExists,
|
||||
Values: []string{},
|
||||
},
|
||||
{
|
||||
Key: "testIn",
|
||||
Operator: metav1.LabelSelectorOpIn,
|
||||
Values: []string{
|
||||
"frontend",
|
||||
},
|
||||
},
|
||||
{
|
||||
Key: "pod",
|
||||
Operator: metav1.LabelSelectorOpIn,
|
||||
Values: []string{
|
||||
"b",
|
||||
},
|
||||
},
|
||||
{
|
||||
Key: "ns",
|
||||
Operator: metav1.LabelSelectorOpIn,
|
||||
Values: []string{
|
||||
"t",
|
||||
},
|
||||
},
|
||||
},
|
||||
MatchLabels: commonMatchLabel,
|
||||
},
|
||||
{
|
||||
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||
{
|
||||
Key: "testExists",
|
||||
Operator: metav1.LabelSelectorOpExists,
|
||||
Values: []string{},
|
||||
},
|
||||
{
|
||||
Key: "testIn",
|
||||
Operator: metav1.LabelSelectorOpIn,
|
||||
Values: []string{
|
||||
"frontend",
|
||||
},
|
||||
},
|
||||
{
|
||||
Key: "pod",
|
||||
Operator: metav1.LabelSelectorOpIn,
|
||||
Values: []string{
|
||||
"b",
|
||||
},
|
||||
},
|
||||
{
|
||||
Key: "ns",
|
||||
Operator: metav1.LabelSelectorOpIn,
|
||||
Values: []string{
|
||||
"y",
|
||||
},
|
||||
},
|
||||
},
|
||||
MatchLabels: commonMatchLabel,
|
||||
},
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(expectedSelectors, testSelectors) {
|
||||
t.Errorf("TestFlattenNameSpaceSelector failed @ 2nd selector deepEqual check.\n Expected: %+v \n Actual: %+v", expectedSelectors, testSelectors)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFlattenNameSpaceSelectorWoMatchLabels(t *testing.T) {
|
||||
firstSelector := &metav1.LabelSelector{
|
||||
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||
{
|
||||
Key: "testIn",
|
||||
Operator: metav1.LabelSelectorOpIn,
|
||||
Values: []string{
|
||||
"backend",
|
||||
},
|
||||
},
|
||||
{
|
||||
Key: "pod",
|
||||
Operator: metav1.LabelSelectorOpIn,
|
||||
Values: []string{
|
||||
"a",
|
||||
},
|
||||
},
|
||||
{
|
||||
Key: "testExists",
|
||||
Operator: metav1.LabelSelectorOpExists,
|
||||
Values: []string{},
|
||||
},
|
||||
{
|
||||
Key: "ns",
|
||||
Operator: metav1.LabelSelectorOpIn,
|
||||
Values: []string{
|
||||
"t",
|
||||
"y",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
testSelectors := FlattenNameSpaceSelector(firstSelector)
|
||||
if len(testSelectors) != 2 {
|
||||
t.Errorf("TestFlattenNameSpaceSelector failed @ 1st selector length check %+v", testSelectors)
|
||||
}
|
||||
|
||||
expectedSelectors := []metav1.LabelSelector{
|
||||
{
|
||||
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||
{
|
||||
Key: "testIn",
|
||||
Operator: metav1.LabelSelectorOpIn,
|
||||
Values: []string{
|
||||
"backend",
|
||||
},
|
||||
},
|
||||
{
|
||||
Key: "pod",
|
||||
Operator: metav1.LabelSelectorOpIn,
|
||||
Values: []string{
|
||||
"a",
|
||||
},
|
||||
},
|
||||
{
|
||||
Key: "testExists",
|
||||
Operator: metav1.LabelSelectorOpExists,
|
||||
Values: []string{},
|
||||
},
|
||||
{
|
||||
Key: "ns",
|
||||
Operator: metav1.LabelSelectorOpIn,
|
||||
Values: []string{
|
||||
"t",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||
{
|
||||
Key: "testIn",
|
||||
Operator: metav1.LabelSelectorOpIn,
|
||||
Values: []string{
|
||||
"backend",
|
||||
},
|
||||
},
|
||||
{
|
||||
Key: "pod",
|
||||
Operator: metav1.LabelSelectorOpIn,
|
||||
Values: []string{
|
||||
"a",
|
||||
},
|
||||
},
|
||||
{
|
||||
Key: "testExists",
|
||||
Operator: metav1.LabelSelectorOpExists,
|
||||
Values: []string{},
|
||||
},
|
||||
{
|
||||
Key: "ns",
|
||||
Operator: metav1.LabelSelectorOpIn,
|
||||
Values: []string{
|
||||
"y",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(testSelectors, expectedSelectors) {
|
||||
t.Errorf("TestFlattenNameSpaceSelector failed @ 1st selector deepEqual check.\n Expected: %+v \n Actual: %+v", expectedSelectors, testSelectors)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,506 @@
|
|||
package translation
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/Azure/azure-container-networking/npm/pkg/dataplane/ipsets"
|
||||
"github.com/Azure/azure-container-networking/npm/pkg/dataplane/policies"
|
||||
"github.com/Azure/azure-container-networking/npm/util"
|
||||
networkingv1 "k8s.io/api/networking/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/klog"
|
||||
)
|
||||
|
||||
/*
|
||||
TODO
|
||||
1. namespace is default in label in K8s. Need to check whether I missed something.
|
||||
- Targeting a Namespace by its name
|
||||
(https://kubernetes.io/docs/concepts/services-networking/network-policies/#targeting-a-namespace-by-its-name)
|
||||
2. Check possible error - first check see how K8s guarantees correctness of the submitted network policy
|
||||
- Return error and validation
|
||||
3. Need to handle 0.0.0.0/0 in IPBlock field
|
||||
- Ipset doesn't allow 0.0.0.0/0 to be added. A general solution is split 0.0.0.0/1 in half which convert to
|
||||
1.0.0.0/1 and 128.0.0.0/1 in linux
|
||||
*/
|
||||
|
||||
var errUnknownPortType = errors.New("unknown port Type")
|
||||
|
||||
type netpolPortType string
|
||||
|
||||
const (
|
||||
numericPortType netpolPortType = "validport"
|
||||
namedPortType netpolPortType = "namedport"
|
||||
included bool = true
|
||||
ipBlocksetNameFormat = "%s-in-ns-%s-%d%s"
|
||||
onlyKeyLabel = 1
|
||||
keyValueLabel = 2
|
||||
)
|
||||
|
||||
func portType(portRule networkingv1.NetworkPolicyPort) (netpolPortType, error) {
|
||||
if portRule.Port == nil || portRule.Port.IntValue() != 0 {
|
||||
return numericPortType, nil
|
||||
} else if portRule.Port.IntValue() == 0 && portRule.Port.String() != "" {
|
||||
return namedPortType, nil
|
||||
}
|
||||
// TODO (jungukcho): check whether this can be possible or not.
|
||||
return "", errUnknownPortType
|
||||
}
|
||||
|
||||
func numericPortRule(portRule *networkingv1.NetworkPolicyPort) (portRuleInfo policies.Ports, protocol string) {
|
||||
portRuleInfo = policies.Ports{}
|
||||
protocol = "TCP"
|
||||
if portRule.Protocol != nil {
|
||||
protocol = string(*portRule.Protocol)
|
||||
}
|
||||
|
||||
if portRule.Port == nil {
|
||||
return portRuleInfo, protocol
|
||||
}
|
||||
|
||||
portRuleInfo.Port = int32(portRule.Port.IntValue())
|
||||
if portRule.EndPort != nil {
|
||||
portRuleInfo.EndPort = *portRule.EndPort
|
||||
}
|
||||
|
||||
return portRuleInfo, protocol
|
||||
}
|
||||
|
||||
func namedPortRuleInfo(portRule *networkingv1.NetworkPolicyPort) (namedPortIPSet *ipsets.TranslatedIPSet, protocol string) {
|
||||
if portRule == nil {
|
||||
return nil, ""
|
||||
}
|
||||
|
||||
protocol = "TCP"
|
||||
if portRule.Protocol != nil {
|
||||
protocol = string(*portRule.Protocol)
|
||||
}
|
||||
|
||||
if portRule.Port == nil {
|
||||
return nil, protocol
|
||||
}
|
||||
|
||||
namedPortIPSet = ipsets.NewTranslatedIPSet(util.NamedPortIPSetPrefix+portRule.Port.String(), ipsets.NamedPorts, []string{})
|
||||
return namedPortIPSet, protocol
|
||||
}
|
||||
|
||||
func namedPortRule(portRule *networkingv1.NetworkPolicyPort) (*ipsets.TranslatedIPSet, policies.SetInfo, string) {
|
||||
if portRule == nil {
|
||||
return nil, policies.SetInfo{}, ""
|
||||
}
|
||||
|
||||
namedPortIPSet, protocol := namedPortRuleInfo(portRule)
|
||||
setInfo := policies.NewSetInfo(util.NamedPortIPSetPrefix+portRule.Port.String(), ipsets.NamedPorts, included, policies.DstDstMatch)
|
||||
return namedPortIPSet, setInfo, protocol
|
||||
}
|
||||
|
||||
func portRule(ruleIPSets []*ipsets.TranslatedIPSet, acl *policies.ACLPolicy, portRule *networkingv1.NetworkPolicyPort, portType netpolPortType) []*ipsets.TranslatedIPSet {
|
||||
if portType == namedPortType {
|
||||
namedPortIPSet, namedPortRuleDstList, protocol := namedPortRule(portRule)
|
||||
acl.DstList = append(acl.DstList, namedPortRuleDstList)
|
||||
acl.Protocol = policies.Protocol(protocol)
|
||||
ruleIPSets = append(ruleIPSets, namedPortIPSet)
|
||||
} else if portType == numericPortType {
|
||||
portInfo, protocol := numericPortRule(portRule)
|
||||
acl.DstPorts = portInfo
|
||||
acl.Protocol = policies.Protocol(protocol)
|
||||
}
|
||||
|
||||
return ruleIPSets
|
||||
}
|
||||
|
||||
func ipBlockSetName(policyName, ns string, direction policies.Direction, ipBlockSetIndex int) string {
|
||||
return fmt.Sprintf(ipBlocksetNameFormat, policyName, ns, ipBlockSetIndex, direction)
|
||||
}
|
||||
|
||||
func ipBlockIPSet(policyName, ns string, direction policies.Direction, ipBlockSetIndex int, ipBlockRule *networkingv1.IPBlock) *ipsets.TranslatedIPSet {
|
||||
if ipBlockRule == nil || ipBlockRule.CIDR == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
members := make([]string, len(ipBlockRule.Except)+1) // except + cidr
|
||||
cidrIndex := 0
|
||||
members[cidrIndex] = ipBlockRule.CIDR
|
||||
for i := 0; i < len(ipBlockRule.Except); i++ {
|
||||
members[i+1] = ipBlockRule.Except[i] + util.IpsetNomatch
|
||||
}
|
||||
|
||||
ipBlockIPSetName := ipBlockSetName(policyName, ns, direction, ipBlockSetIndex)
|
||||
ipBlockIPSet := ipsets.NewTranslatedIPSet(ipBlockIPSetName, ipsets.CIDRBlocks, members)
|
||||
return ipBlockIPSet
|
||||
}
|
||||
|
||||
func ipBlockRule(policyName, ns string, direction policies.Direction, ipBlockSetIndex int, ipBlockRule *networkingv1.IPBlock) (*ipsets.TranslatedIPSet, policies.SetInfo) {
|
||||
if ipBlockRule == nil || ipBlockRule.CIDR == "" {
|
||||
return nil, policies.SetInfo{}
|
||||
}
|
||||
|
||||
ipBlockIPSet := ipBlockIPSet(policyName, ns, direction, ipBlockSetIndex, ipBlockRule)
|
||||
setInfo := policies.NewSetInfo(ipBlockIPSet.Metadata.Name, ipsets.CIDRBlocks, included, policies.SrcMatch)
|
||||
return ipBlockIPSet, setInfo
|
||||
}
|
||||
|
||||
func podLabelType(label string) ipsets.SetType {
|
||||
// TODO(jungukcho): this is unnecessary function which has extra computation
|
||||
// will be removed after optimizing parseSelector function
|
||||
labels := strings.Split(label, ":")
|
||||
switch LenOfLabels := len(labels); LenOfLabels {
|
||||
case onlyKeyLabel:
|
||||
return ipsets.KeyLabelOfPod
|
||||
case keyValueLabel:
|
||||
return ipsets.KeyValueLabelOfPod
|
||||
default: // in case of nested value (i.e., len(labels) >= 3
|
||||
return ipsets.NestedLabelOfPod
|
||||
}
|
||||
}
|
||||
|
||||
// podSelectorRule return srcList for ACL by using ops and labelsForSpec
|
||||
func podSelectorRule(matchType policies.MatchType, ops, ipSetForACL []string) []policies.SetInfo {
|
||||
podSelectorList := []policies.SetInfo{}
|
||||
for i := 0; i < len(ipSetForACL); i++ {
|
||||
noOp := ops[i] == ""
|
||||
labelType := podLabelType(ipSetForACL[i])
|
||||
setInfo := policies.NewSetInfo(ipSetForACL[i], labelType, noOp, matchType)
|
||||
podSelectorList = append(podSelectorList, setInfo)
|
||||
}
|
||||
return podSelectorList
|
||||
}
|
||||
|
||||
func podSelectorIPSets(ipSetForSingleVal []string, ipSetNameForMultiVal map[string][]string) []*ipsets.TranslatedIPSet {
|
||||
podSelectorIPSets := []*ipsets.TranslatedIPSet{}
|
||||
for _, hashSetName := range ipSetForSingleVal {
|
||||
labelType := podLabelType(hashSetName)
|
||||
ipset := ipsets.NewTranslatedIPSet(hashSetName, labelType, []string{})
|
||||
podSelectorIPSets = append(podSelectorIPSets, ipset)
|
||||
}
|
||||
|
||||
for listSetName, hashIPSetList := range ipSetNameForMultiVal {
|
||||
ipset := ipsets.NewTranslatedIPSet(listSetName, ipsets.NestedLabelOfPod, hashIPSetList)
|
||||
podSelectorIPSets = append(podSelectorIPSets, ipset)
|
||||
}
|
||||
|
||||
return podSelectorIPSets
|
||||
}
|
||||
|
||||
func targetPodSelectorInfo(selector *metav1.LabelSelector) (ops, ipSetForACL, ipSetForSingleVal []string, ipSetNameForMultiVal map[string][]string) {
|
||||
// TODO(jungukcho) : need to revise parseSelector function to reduce computations and enhance readability
|
||||
// 1. use better variables to indicate included instead of "".
|
||||
// 2. Classify type of set in parseSelector to avoid multiple computations
|
||||
// 3. Resolve makezero lint errors (nozero)
|
||||
singleValueLabelsWithOps, multiValuesLabelsWithOps := parseSelector(selector)
|
||||
ops, ipSetForSingleVal = GetOperatorsAndLabels(singleValueLabelsWithOps)
|
||||
|
||||
ipSetNameForMultiVal = make(map[string][]string)
|
||||
LenOfIPSetForACL := len(ipSetForSingleVal) + len(multiValuesLabelsWithOps)
|
||||
ipSetForACL = make([]string, LenOfIPSetForACL)
|
||||
IndexOfIPSetForACL := copy(ipSetForACL, ipSetForSingleVal)
|
||||
|
||||
for multiValueLabelKeyWithOps, multiValueLabelList := range multiValuesLabelsWithOps {
|
||||
op, multiValueLabelKey := GetOperatorAndLabel(multiValueLabelKeyWithOps)
|
||||
ops = append(ops, op) // nozero
|
||||
|
||||
ipSetNameForMultiValueLabel := getSetNameForMultiValueSelector(multiValueLabelKey, multiValueLabelList)
|
||||
ipSetForACL[IndexOfIPSetForACL] = ipSetNameForMultiValueLabel
|
||||
IndexOfIPSetForACL++
|
||||
|
||||
for _, labelValue := range multiValueLabelList {
|
||||
ipsetName := util.GetIpSetFromLabelKV(multiValueLabelKey, labelValue)
|
||||
ipSetForSingleVal = append(ipSetForSingleVal, ipsetName) // nozero
|
||||
ipSetNameForMultiVal[ipSetNameForMultiValueLabel] = append(ipSetNameForMultiVal[ipSetNameForMultiValueLabel], ipsetName)
|
||||
}
|
||||
}
|
||||
return ops, ipSetForACL, ipSetForSingleVal, ipSetNameForMultiVal
|
||||
}
|
||||
|
||||
func allPodsSelectorInNs(ns string, matchType policies.MatchType) ([]*ipsets.TranslatedIPSet, []policies.SetInfo) {
|
||||
// TODO(jungukcho): important this is common component - double-check whether it has duplicated one or not
|
||||
ipset := ipsets.NewTranslatedIPSet(ns, ipsets.Namespace, []string{})
|
||||
podSelectorIPSets := []*ipsets.TranslatedIPSet{ipset}
|
||||
|
||||
setInfo := policies.NewSetInfo(ns, ipsets.Namespace, included, matchType)
|
||||
podSelectorList := []policies.SetInfo{setInfo}
|
||||
return podSelectorIPSets, podSelectorList
|
||||
}
|
||||
|
||||
func targetPodSelector(ns string, matchType policies.MatchType, selector *metav1.LabelSelector) ([]*ipsets.TranslatedIPSet, []policies.SetInfo) {
|
||||
// (TODO): some data in singleValueLabels and multiValuesLabels are duplicated
|
||||
ops, ipSetForACL, ipSetForSingleVal, ipSetNameForMultiVal := targetPodSelectorInfo(selector)
|
||||
// select all pods in a namespace
|
||||
if len(ops) == 1 && len(ipSetForSingleVal) == 1 && ops[0] == "" && ipSetForSingleVal[0] == "" {
|
||||
podSelectorIPSets, podSelectorList := allPodsSelectorInNs(ns, matchType)
|
||||
return podSelectorIPSets, podSelectorList
|
||||
}
|
||||
|
||||
// TODO(jungukcho): may need to check ordering hashset and listset if ipSetNameForMultiVal exists.
|
||||
// refer to last test set in TestPodSelectorIPSets
|
||||
podSelectorIPSets := podSelectorIPSets(ipSetForSingleVal, ipSetNameForMultiVal)
|
||||
podSelectorList := podSelectorRule(matchType, ops, ipSetForACL)
|
||||
return podSelectorIPSets, podSelectorList
|
||||
}
|
||||
|
||||
func nsLabelType(label string) ipsets.SetType {
|
||||
// TODO(jungukcho): this is unnecessary function which has extra computation
|
||||
// will be removed after optimizing parseSelector function
|
||||
labels := strings.Split(label, ":")
|
||||
if len(labels) == onlyKeyLabel {
|
||||
return ipsets.KeyLabelOfNamespace
|
||||
} else if len(labels) == keyValueLabel {
|
||||
return ipsets.KeyValueLabelOfNamespace
|
||||
}
|
||||
|
||||
// (TODO): check whether this is possible
|
||||
return ipsets.UnknownType
|
||||
}
|
||||
|
||||
func nameSpaceSelectorRule(matchType policies.MatchType, ops, nsSelectorInfo []string) []policies.SetInfo {
|
||||
nsSelectorList := []policies.SetInfo{}
|
||||
for i := 0; i < len(nsSelectorInfo); i++ {
|
||||
noOp := ops[i] == ""
|
||||
labelType := nsLabelType(nsSelectorInfo[i])
|
||||
setInfo := policies.NewSetInfo(nsSelectorInfo[i], labelType, noOp, matchType)
|
||||
nsSelectorList = append(nsSelectorList, setInfo)
|
||||
}
|
||||
return nsSelectorList
|
||||
}
|
||||
|
||||
func nameSpaceSelectorIPSets(singleValueLabels []string) []*ipsets.TranslatedIPSet {
|
||||
nsSelectorIPSets := []*ipsets.TranslatedIPSet{}
|
||||
for _, listSet := range singleValueLabels {
|
||||
labelType := nsLabelType(listSet)
|
||||
translatedIPSet := ipsets.NewTranslatedIPSet(listSet, labelType, []string{})
|
||||
nsSelectorIPSets = append(nsSelectorIPSets, translatedIPSet)
|
||||
}
|
||||
return nsSelectorIPSets
|
||||
}
|
||||
|
||||
func nameSpaceSelectorInfo(selector *metav1.LabelSelector) (ops, singleValueLabels []string) {
|
||||
// parse namespace label selector.
|
||||
// Ignore multiple values from parseSelector since Namespace selector does not have multiple values.
|
||||
// TODO(jungukcho): will revise parseSelector for easy understanding between podSelector and namespaceSelector
|
||||
singleValueLabelsWithOps, _ := parseSelector(selector)
|
||||
ops, singleValueLabels = GetOperatorsAndLabels(singleValueLabelsWithOps)
|
||||
return ops, singleValueLabels
|
||||
}
|
||||
|
||||
func allNameSpaceRule(matchType policies.MatchType) ([]*ipsets.TranslatedIPSet, []policies.SetInfo) {
|
||||
translatedIPSet := ipsets.NewTranslatedIPSet(util.KubeAllNamespacesFlag, ipsets.Namespace, []string{})
|
||||
nsSelectorIPSets := []*ipsets.TranslatedIPSet{translatedIPSet}
|
||||
|
||||
setInfo := policies.NewSetInfo(util.KubeAllNamespacesFlag, ipsets.Namespace, included, matchType)
|
||||
nsSelectorList := []policies.SetInfo{setInfo}
|
||||
return nsSelectorIPSets, nsSelectorList
|
||||
}
|
||||
|
||||
func nameSpaceSelector(matchType policies.MatchType, selector *metav1.LabelSelector) ([]*ipsets.TranslatedIPSet, []policies.SetInfo) {
|
||||
ops, singleValueLabels := nameSpaceSelectorInfo(selector)
|
||||
|
||||
if len(ops) == 1 && len(singleValueLabels) == 1 && ops[0] == "" && singleValueLabels[0] == "" {
|
||||
nsSelectorIPSets, nsSelectorList := allNameSpaceRule(matchType)
|
||||
return nsSelectorIPSets, nsSelectorList
|
||||
}
|
||||
|
||||
nsSelectorIPSets := nameSpaceSelectorIPSets(singleValueLabels)
|
||||
nsSelectorList := nameSpaceSelectorRule(matchType, ops, singleValueLabels)
|
||||
return nsSelectorIPSets, nsSelectorList
|
||||
}
|
||||
|
||||
func allowAllTraffic(matchType policies.MatchType) (*ipsets.TranslatedIPSet, policies.SetInfo) {
|
||||
allowAllIPSets := ipsets.NewTranslatedIPSet(util.KubeAllNamespacesFlag, ipsets.Namespace, []string{})
|
||||
setInfo := policies.NewSetInfo(util.KubeAllNamespacesFlag, ipsets.Namespace, included, matchType)
|
||||
return allowAllIPSets, setInfo
|
||||
}
|
||||
|
||||
func defaultDropACL(policyNS, policyName string, direction policies.Direction) *policies.ACLPolicy {
|
||||
dropACL := policies.NewACLPolicy(policyNS, policyName, policies.Dropped, direction)
|
||||
return dropACL
|
||||
}
|
||||
|
||||
// ruleExists returns type of rules from networkingv1.NetworkPolicyIngressRule or networkingv1.NetworkPolicyEgressRule
|
||||
func ruleExists(ports []networkingv1.NetworkPolicyPort, peer []networkingv1.NetworkPolicyPeer) (allowExternal, portRuleExists, peerRuleExists bool) {
|
||||
// TODO(jungukcho): need to clarify and summarize below flags
|
||||
portRuleExists = len(ports) > 0
|
||||
if peer != nil {
|
||||
if len(peer) == 0 {
|
||||
peerRuleExists = true
|
||||
allowExternal = true
|
||||
}
|
||||
|
||||
for _, peerRule := range peer {
|
||||
if peerRule.PodSelector != nil ||
|
||||
peerRule.NamespaceSelector != nil ||
|
||||
peerRule.IPBlock != nil {
|
||||
peerRuleExists = true
|
||||
break
|
||||
}
|
||||
}
|
||||
} else if !portRuleExists {
|
||||
allowExternal = true
|
||||
}
|
||||
|
||||
return allowExternal, portRuleExists, peerRuleExists
|
||||
}
|
||||
|
||||
func peerAndPortRule(npmNetPol *policies.NPMNetworkPolicy, ports []networkingv1.NetworkPolicyPort, setInfo []policies.SetInfo) {
|
||||
if len(ports) == 0 {
|
||||
acl := policies.NewACLPolicy(npmNetPol.NameSpace, npmNetPol.Name, policies.Allowed, policies.Ingress)
|
||||
acl.SrcList = setInfo
|
||||
npmNetPol.ACLs = append(npmNetPol.ACLs, acl)
|
||||
return
|
||||
}
|
||||
|
||||
for i := range ports {
|
||||
portKind, err := portType(ports[i])
|
||||
if err != nil {
|
||||
// TODO(jungukcho): handle error
|
||||
klog.Infof("Invalid NetworkPolicyPort %s", err)
|
||||
continue
|
||||
}
|
||||
|
||||
acl := policies.NewACLPolicy(npmNetPol.NameSpace, npmNetPol.Name, policies.Allowed, policies.Ingress)
|
||||
acl.SrcList = setInfo
|
||||
npmNetPol.RuleIPSets = portRule(npmNetPol.RuleIPSets, acl, &ports[i], portKind)
|
||||
npmNetPol.ACLs = append(npmNetPol.ACLs, acl)
|
||||
}
|
||||
}
|
||||
|
||||
func translateIngress(npmNetPol *policies.NPMNetworkPolicy, targetSelector *metav1.LabelSelector, rules []networkingv1.NetworkPolicyIngressRule) {
|
||||
// TODO(jungukcho) : Double-check addedCidrEntry.
|
||||
var addedCidrEntry bool // all cidr entry will be added in one set per from/to rule
|
||||
npmNetPol.PodSelectorIPSets, npmNetPol.PodSelectorList = targetPodSelector(npmNetPol.NameSpace, policies.DstMatch, targetSelector)
|
||||
|
||||
for i, rule := range rules {
|
||||
allowExternal, portRuleExists, fromRuleExists := ruleExists(rule.Ports, rule.From)
|
||||
|
||||
// #0. TODO(jungukcho): cannot come up when this condition is met.
|
||||
if !portRuleExists && !fromRuleExists && !allowExternal {
|
||||
acl := policies.NewACLPolicy(npmNetPol.NameSpace, npmNetPol.Name, policies.Allowed, policies.Ingress)
|
||||
ruleIPSets, setInfo := allowAllTraffic(policies.SrcMatch)
|
||||
npmNetPol.RuleIPSets = append(npmNetPol.RuleIPSets, ruleIPSets)
|
||||
acl.SrcList = append(acl.SrcList, setInfo)
|
||||
npmNetPol.ACLs = append(npmNetPol.ACLs, acl)
|
||||
continue
|
||||
}
|
||||
|
||||
// #1. Only Ports fields exist in rule
|
||||
if portRuleExists && !fromRuleExists && !allowExternal {
|
||||
for i := range rule.Ports {
|
||||
portKind, err := portType(rule.Ports[i])
|
||||
if err != nil {
|
||||
klog.Infof("Invalid NetworkPolicyPort %s", err)
|
||||
continue
|
||||
}
|
||||
|
||||
portACL := policies.NewACLPolicy(npmNetPol.NameSpace, npmNetPol.Name, policies.Allowed, policies.Ingress)
|
||||
npmNetPol.RuleIPSets = portRule(npmNetPol.RuleIPSets, portACL, &rule.Ports[i], portKind)
|
||||
npmNetPol.ACLs = append(npmNetPol.ACLs, portACL)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// #2. From fields exist in rule
|
||||
for j, fromRule := range rule.From {
|
||||
// #2.1 Handle IPBlock and port if exist
|
||||
if fromRule.IPBlock != nil {
|
||||
if len(fromRule.IPBlock.CIDR) > 0 {
|
||||
// TODO(jungukcho): check this - need UTs
|
||||
// TODO(jungukcho): need a const for "in"
|
||||
ipBlockIPSet, ipBlockSetInfo := ipBlockRule(npmNetPol.Name, npmNetPol.NameSpace, policies.Ingress, i, fromRule.IPBlock)
|
||||
npmNetPol.RuleIPSets = append(npmNetPol.RuleIPSets, ipBlockIPSet)
|
||||
if j != 0 && addedCidrEntry {
|
||||
continue
|
||||
}
|
||||
peerAndPortRule(npmNetPol, rule.Ports, []policies.SetInfo{ipBlockSetInfo})
|
||||
addedCidrEntry = true
|
||||
}
|
||||
// Do not check further since IPBlock filed is exclusive field.
|
||||
continue
|
||||
}
|
||||
|
||||
// if there is no podSelector or namespaceSelector in fromRule, no need to check below code.
|
||||
if fromRule.PodSelector == nil && fromRule.NamespaceSelector == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// #2.2 handle nameSpaceSelector and port if exist
|
||||
if fromRule.PodSelector == nil && fromRule.NamespaceSelector != nil {
|
||||
flattenNSSelctor := FlattenNameSpaceSelector(fromRule.NamespaceSelector)
|
||||
for i := range flattenNSSelctor {
|
||||
nsSelectorIPSets, nsSrcList := nameSpaceSelector(policies.SrcMatch, &flattenNSSelctor[i])
|
||||
npmNetPol.RuleIPSets = append(npmNetPol.RuleIPSets, nsSelectorIPSets...)
|
||||
peerAndPortRule(npmNetPol, rule.Ports, nsSrcList)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// #2.3 handle podSelector and port if exist
|
||||
if fromRule.PodSelector != nil && fromRule.NamespaceSelector == nil {
|
||||
// TODO check old code if we need any ns- prefix for pod selectors
|
||||
podSelectorIPSets, podSelectorSrcList := targetPodSelector(npmNetPol.NameSpace, policies.SrcMatch, fromRule.PodSelector)
|
||||
npmNetPol.RuleIPSets = append(npmNetPol.RuleIPSets, podSelectorIPSets...)
|
||||
peerAndPortRule(npmNetPol, rule.Ports, podSelectorSrcList)
|
||||
continue
|
||||
}
|
||||
|
||||
// fromRule has both namespaceSelector and podSelector set.
|
||||
// We should match the selected pods in the selected namespaces.
|
||||
// This allows traffic from podSelector intersects namespaceSelector
|
||||
// This is only supported in kubernetes version >= 1.11
|
||||
if !util.IsNewNwPolicyVerFlag {
|
||||
continue
|
||||
}
|
||||
|
||||
// #2.4 handle namespaceSelector and podSelector and port if exist
|
||||
podSelectorIPSets, podSelectorSrcList := targetPodSelector(npmNetPol.NameSpace, policies.SrcMatch, fromRule.PodSelector)
|
||||
npmNetPol.RuleIPSets = append(npmNetPol.RuleIPSets, podSelectorIPSets...)
|
||||
|
||||
flattenNSSelctor := FlattenNameSpaceSelector(fromRule.NamespaceSelector)
|
||||
for i := range flattenNSSelctor {
|
||||
nsSelectorIPSets, nsSrcList := nameSpaceSelector(policies.SrcMatch, &flattenNSSelctor[i])
|
||||
npmNetPol.RuleIPSets = append(npmNetPol.RuleIPSets, nsSelectorIPSets...)
|
||||
nsSrcList = append(nsSrcList, podSelectorSrcList...)
|
||||
peerAndPortRule(npmNetPol, rule.Ports, nsSrcList)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(jungukcho): move this code in entry point of this function?
|
||||
if allowExternal {
|
||||
allowExternalACL := policies.NewACLPolicy(npmNetPol.NameSpace, npmNetPol.Name, policies.Allowed, policies.Ingress)
|
||||
npmNetPol.ACLs = append(npmNetPol.ACLs, allowExternalACL)
|
||||
}
|
||||
}
|
||||
|
||||
klog.Info("finished parsing ingress rule")
|
||||
}
|
||||
|
||||
func existIngress(npObj *networkingv1.NetworkPolicy) bool { //nolint:unused //it will be called from v2 networkPolicyController which will come in next PR
|
||||
return !(npObj.Spec.Ingress != nil &&
|
||||
len(npObj.Spec.Ingress) == 1 &&
|
||||
len(npObj.Spec.Ingress[0].Ports) == 0 &&
|
||||
len(npObj.Spec.Ingress[0].From) == 0)
|
||||
}
|
||||
|
||||
func translatePolicy(npObj *networkingv1.NetworkPolicy) *policies.NPMNetworkPolicy { //nolint:deadcode,unused //it will be called from v2 networkPolicyController which will come in next PR
|
||||
npmNetPol := &policies.NPMNetworkPolicy{
|
||||
Name: npObj.ObjectMeta.Name,
|
||||
NameSpace: npObj.ObjectMeta.Namespace,
|
||||
}
|
||||
|
||||
if len(npObj.Spec.PolicyTypes) == 0 {
|
||||
translateIngress(npmNetPol, &npObj.Spec.PodSelector, npObj.Spec.Ingress)
|
||||
return npmNetPol
|
||||
}
|
||||
|
||||
for _, ptype := range npObj.Spec.PolicyTypes {
|
||||
if ptype == networkingv1.PolicyTypeIngress {
|
||||
translateIngress(npmNetPol, &npObj.Spec.PodSelector, npObj.Spec.Ingress)
|
||||
}
|
||||
}
|
||||
|
||||
if hasIngress := existIngress(npObj); hasIngress {
|
||||
dropACL := defaultDropACL(npmNetPol.NameSpace, npmNetPol.Name, policies.Ingress)
|
||||
npmNetPol.ACLs = append(npmNetPol.ACLs, dropACL)
|
||||
}
|
||||
|
||||
return npmNetPol
|
||||
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -377,7 +377,7 @@ func (dp *DataPlane) deleteIPSetsAndReferences(sets []*ipsets.TranslatedIPSet, n
|
|||
return npmerrors.Errorf(npmErrorString, false, fmt.Sprintf("[dataplane] failed to RemoveFromSet in deleteIPSetReferences with err: %s", err.Error()))
|
||||
}
|
||||
}
|
||||
} else if ipsets.GetSetKind(set.Metadata.Type) == ipsets.ListSet && len(set.Members) > 0 {
|
||||
} else if set.Metadata.GetSetKind() == ipsets.ListSet && len(set.Members) > 0 {
|
||||
// Delete if any 2nd level IPSets are generated by Controller with members
|
||||
err := dp.ipsetMgr.RemoveFromList(set.Metadata, getMembersOfTranslatedSets(set.Members))
|
||||
if err != nil {
|
||||
|
|
|
@ -10,35 +10,90 @@ import (
|
|||
npmerrors "github.com/Azure/azure-container-networking/npm/util/errors"
|
||||
)
|
||||
|
||||
type IPSet struct {
|
||||
Name string
|
||||
HashedName string
|
||||
// SetProperties embedding set properties
|
||||
SetProperties
|
||||
// IpPodKey is used for setMaps to store Ips and ports as keys
|
||||
// and podKey as value
|
||||
IPPodKey map[string]string
|
||||
// This is used for listMaps to store child IP Sets
|
||||
MemberIPSets map[string]*IPSet
|
||||
// Using a map to emulate set and value as struct{} for
|
||||
// minimal memory consumption
|
||||
// SelectorReference holds networkpolicy names where this IPSet
|
||||
// is being used in PodSelector and NameSpace
|
||||
SelectorReference map[string]struct{}
|
||||
// NetPolReference holds networkpolicy names where this IPSet
|
||||
// is being referred as part of rules
|
||||
NetPolReference map[string]struct{}
|
||||
// ipsetReferCount keeps track of how many lists in the cache refer to this ipset
|
||||
ipsetReferCount int
|
||||
// kernelReferCount keeps track of how many lists in the kernel refer to this ipset
|
||||
kernelReferCount int
|
||||
}
|
||||
|
||||
type IPSetMetadata struct {
|
||||
Name string
|
||||
Type SetType
|
||||
}
|
||||
|
||||
type SetKind string
|
||||
|
||||
const (
|
||||
// ListSet is of kind list with members as other IPSets
|
||||
ListSet SetKind = "list"
|
||||
// HashSet is of kind hashset with members as IPs and/or port
|
||||
HashSet SetKind = "set"
|
||||
// UnknownKind is returned when kind is unknown
|
||||
UnknownKind SetKind = "unknown"
|
||||
)
|
||||
|
||||
// NewIPSetMetadata is used for controllers to send in skeleton ipsets to DP
|
||||
func NewIPSetMetadata(name string, setType SetType) *IPSetMetadata {
|
||||
set := &IPSetMetadata{
|
||||
Name: name,
|
||||
Type: setType,
|
||||
}
|
||||
return set
|
||||
}
|
||||
|
||||
func (setMetadata *IPSetMetadata) GetHashedName() string {
|
||||
// TODO(jungukcho): I think this is unnecessary code.
|
||||
prefixedName := setMetadata.GetPrefixName()
|
||||
if prefixedName == Unknown {
|
||||
return Unknown
|
||||
}
|
||||
return util.GetHashedName(prefixedName)
|
||||
}
|
||||
|
||||
func (setMetadata *IPSetMetadata) GetPrefixName() string {
|
||||
switch setMetadata.Type {
|
||||
case CIDRBlocks:
|
||||
return fmt.Sprintf("%s%s", util.CIDRPrefix, setMetadata.Name)
|
||||
case Namespace:
|
||||
return fmt.Sprintf("%s%s", util.NamespacePrefix, setMetadata.Name)
|
||||
case NamedPorts:
|
||||
return fmt.Sprintf("%s%s", util.NamedPortIPSetPrefix, setMetadata.Name)
|
||||
case KeyLabelOfPod:
|
||||
return fmt.Sprintf("%s%s", util.PodLabelPrefix, setMetadata.Name)
|
||||
case KeyValueLabelOfPod:
|
||||
return fmt.Sprintf("%s%s", util.PodLabelPrefix, setMetadata.Name)
|
||||
case KeyLabelOfNamespace:
|
||||
return fmt.Sprintf("%s%s", util.NamespaceLabelPrefix, setMetadata.Name)
|
||||
case KeyValueLabelOfNamespace:
|
||||
return fmt.Sprintf("%s%s", util.NamespaceLabelPrefix, setMetadata.Name)
|
||||
case NestedLabelOfPod:
|
||||
return fmt.Sprintf("%s%s", util.NestedLabelPrefix, setMetadata.Name)
|
||||
case UnknownType: // adding this to appease golint
|
||||
return Unknown
|
||||
default:
|
||||
return Unknown
|
||||
}
|
||||
}
|
||||
|
||||
func (setMetadata *IPSetMetadata) GetSetKind() SetKind {
|
||||
switch setMetadata.Type {
|
||||
case CIDRBlocks:
|
||||
return HashSet
|
||||
case Namespace:
|
||||
return HashSet
|
||||
case NamedPorts:
|
||||
return HashSet
|
||||
case KeyLabelOfPod:
|
||||
return HashSet
|
||||
case KeyValueLabelOfPod:
|
||||
return HashSet
|
||||
case KeyLabelOfNamespace:
|
||||
return ListSet
|
||||
case KeyValueLabelOfNamespace:
|
||||
return ListSet
|
||||
case NestedLabelOfPod:
|
||||
return ListSet
|
||||
case UnknownType: // adding this to appease golint
|
||||
return UnknownKind
|
||||
default:
|
||||
return UnknownKind
|
||||
}
|
||||
}
|
||||
|
||||
// TranslatedIPSet is created by translation engine and provides IPSets used in
|
||||
// network policy. Only 2 types of IPSets are generated with members:
|
||||
// 1. CIDRBlocks IPSet
|
||||
|
@ -52,6 +107,15 @@ type TranslatedIPSet struct {
|
|||
Members []string
|
||||
}
|
||||
|
||||
// NewTranslatedIPSet creates TranslatedIPSet.
|
||||
func NewTranslatedIPSet(name string, setType SetType, members []string) *TranslatedIPSet {
|
||||
translatedIPSet := &TranslatedIPSet{
|
||||
Metadata: NewIPSetMetadata(name, setType),
|
||||
Members: members,
|
||||
}
|
||||
return translatedIPSet
|
||||
}
|
||||
|
||||
type SetProperties struct {
|
||||
// Stores type of ip grouping
|
||||
Type SetType
|
||||
|
@ -107,17 +171,6 @@ func (x SetType) String() string {
|
|||
return setTypeName[x]
|
||||
}
|
||||
|
||||
type SetKind string
|
||||
|
||||
const (
|
||||
// ListSet is of kind list with members as other IPSets
|
||||
ListSet SetKind = "list"
|
||||
// HashSet is of kind hashset with members as IPs and/or port
|
||||
HashSet SetKind = "set"
|
||||
// UnknownKind is returned when kind is unknown
|
||||
UnknownKind SetKind = "unknown"
|
||||
)
|
||||
|
||||
// ReferenceType specifies the kind of reference for an IPSet
|
||||
type ReferenceType string
|
||||
|
||||
|
@ -127,6 +180,30 @@ const (
|
|||
NetPolType ReferenceType = "NetPol"
|
||||
)
|
||||
|
||||
type IPSet struct {
|
||||
Name string
|
||||
HashedName string
|
||||
// SetProperties embedding set properties
|
||||
SetProperties
|
||||
// IpPodKey is used for setMaps to store Ips and ports as keys
|
||||
// and podKey as value
|
||||
IPPodKey map[string]string
|
||||
// This is used for listMaps to store child IP Sets
|
||||
MemberIPSets map[string]*IPSet
|
||||
// Using a map to emulate set and value as struct{} for
|
||||
// minimal memory consumption
|
||||
// SelectorReference holds networkpolicy names where this IPSet
|
||||
// is being used in PodSelector and NameSpace
|
||||
SelectorReference map[string]struct{}
|
||||
// NetPolReference holds networkpolicy names where this IPSet
|
||||
// is being referred as part of rules
|
||||
NetPolReference map[string]struct{}
|
||||
// ipsetReferCount keeps track of how many lists in the cache refer to this ipset
|
||||
ipsetReferCount int
|
||||
// kernelReferCount keeps track of how many lists in the kernel refer to this ipset
|
||||
kernelReferCount int
|
||||
}
|
||||
|
||||
func NewIPSet(setMetadata *IPSetMetadata) *IPSet {
|
||||
prefixedName := setMetadata.GetPrefixName()
|
||||
set := &IPSet{
|
||||
|
@ -134,7 +211,7 @@ func NewIPSet(setMetadata *IPSetMetadata) *IPSet {
|
|||
HashedName: util.GetHashedName(prefixedName),
|
||||
SetProperties: SetProperties{
|
||||
Type: setMetadata.Type,
|
||||
Kind: GetSetKind(setMetadata.Type),
|
||||
Kind: setMetadata.GetSetKind(),
|
||||
},
|
||||
// Map with Key as Network Policy name to to emulate set
|
||||
// and value as struct{} for minimal memory consumption
|
||||
|
@ -153,46 +230,9 @@ func NewIPSet(setMetadata *IPSetMetadata) *IPSet {
|
|||
return set
|
||||
}
|
||||
|
||||
// NewIPSetMetadata is used for controllers to send in skeleton ipsets to DP
|
||||
func NewIPSetMetadata(name string, setType SetType) *IPSetMetadata {
|
||||
set := &IPSetMetadata{
|
||||
Name: name,
|
||||
Type: setType,
|
||||
}
|
||||
return set
|
||||
}
|
||||
|
||||
func (setMetadata *IPSetMetadata) GetPrefixName() string {
|
||||
switch setMetadata.Type {
|
||||
case CIDRBlocks:
|
||||
return fmt.Sprintf("%s%s", util.CIDRPrefix, setMetadata.Name)
|
||||
case Namespace:
|
||||
return fmt.Sprintf("%s%s", util.NamespacePrefix, setMetadata.Name)
|
||||
case NamedPorts:
|
||||
return fmt.Sprintf("%s%s", util.NamedPortIPSetPrefix, setMetadata.Name)
|
||||
case KeyLabelOfPod:
|
||||
return fmt.Sprintf("%s%s", util.PodLabelPrefix, setMetadata.Name)
|
||||
case KeyValueLabelOfPod:
|
||||
return fmt.Sprintf("%s%s", util.PodLabelPrefix, setMetadata.Name)
|
||||
case KeyLabelOfNamespace:
|
||||
return fmt.Sprintf("%s%s", util.NamespaceLabelPrefix, setMetadata.Name)
|
||||
case KeyValueLabelOfNamespace:
|
||||
return fmt.Sprintf("%s%s", util.NamespaceLabelPrefix, setMetadata.Name)
|
||||
case NestedLabelOfPod:
|
||||
return fmt.Sprintf("%s%s", util.NestedLabelPrefix, setMetadata.Name)
|
||||
case UnknownType: // adding this to appease golint
|
||||
return Unknown
|
||||
default:
|
||||
return Unknown
|
||||
}
|
||||
}
|
||||
|
||||
func (setMetadata *IPSetMetadata) GetHashedName() string {
|
||||
prefixedName := setMetadata.GetPrefixName()
|
||||
if prefixedName == Unknown {
|
||||
return Unknown
|
||||
}
|
||||
return util.GetHashedName(prefixedName)
|
||||
func (set *IPSet) String() string {
|
||||
return fmt.Sprintf("Name: %s HashedNamed: %s Type: %s Kind: %s",
|
||||
set.Name, set.HashedName, setTypeName[set.Type], string(set.Kind))
|
||||
}
|
||||
|
||||
func (set *IPSet) GetSetContents() ([]string, error) {
|
||||
|
@ -265,31 +305,6 @@ func (set *IPSet) Compare(newSet *IPSet) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
func GetSetKind(setType SetType) SetKind {
|
||||
switch setType {
|
||||
case CIDRBlocks:
|
||||
return HashSet
|
||||
case Namespace:
|
||||
return HashSet
|
||||
case NamedPorts:
|
||||
return HashSet
|
||||
case KeyLabelOfPod:
|
||||
return HashSet
|
||||
case KeyValueLabelOfPod:
|
||||
return HashSet
|
||||
case KeyLabelOfNamespace:
|
||||
return ListSet
|
||||
case KeyValueLabelOfNamespace:
|
||||
return ListSet
|
||||
case NestedLabelOfPod:
|
||||
return ListSet
|
||||
case UnknownType: // adding this to appease golint
|
||||
return UnknownKind
|
||||
default:
|
||||
return UnknownKind
|
||||
}
|
||||
}
|
||||
|
||||
func (set *IPSet) incIPSetReferCount() {
|
||||
set.ipsetReferCount++
|
||||
}
|
||||
|
|
|
@ -174,9 +174,7 @@ func (pMgr *PolicyManager) getCreatorForInitChains() *ioutil.FileCreator {
|
|||
|
||||
// add AZURE-NPM chain rules
|
||||
creator.AddLine("", nil, util.IptablesAppendFlag, util.IptablesAzureChain, util.IptablesJumpFlag, util.IptablesAzureIngressChain)
|
||||
|
||||
creator.AddLine("", nil, util.IptablesAppendFlag, util.IptablesAzureChain, util.IptablesJumpFlag, util.IptablesAzureEgressChain)
|
||||
|
||||
creator.AddLine("", nil, util.IptablesAppendFlag, util.IptablesAzureChain, util.IptablesJumpFlag, util.IptablesAzureAcceptChain)
|
||||
|
||||
// add AZURE-NPM-INGRESS chain rules
|
||||
|
@ -190,7 +188,6 @@ func (pMgr *PolicyManager) getCreatorForInitChains() *ioutil.FileCreator {
|
|||
markIngressAllowSpecs = append(markIngressAllowSpecs, getSetMarkSpecs(util.IptablesAzureIngressAllowMarkHex)...)
|
||||
markIngressAllowSpecs = append(markIngressAllowSpecs, getCommentSpecs(fmt.Sprintf("SET-INGRESS-ALLOW-MARK-%s", util.IptablesAzureIngressAllowMarkHex))...)
|
||||
creator.AddLine("", nil, markIngressAllowSpecs...)
|
||||
|
||||
creator.AddLine("", nil, util.IptablesAppendFlag, util.IptablesAzureIngressAllowMarkChain, util.IptablesJumpFlag, util.IptablesAzureEgressChain)
|
||||
|
||||
// add AZURE-NPM-EGRESS chain rules
|
||||
|
@ -209,9 +206,7 @@ func (pMgr *PolicyManager) getCreatorForInitChains() *ioutil.FileCreator {
|
|||
clearSpecs = append(clearSpecs, getSetMarkSpecs(util.IptablesAzureClearMarkHex)...)
|
||||
clearSpecs = append(clearSpecs, getCommentSpecs("Clear-AZURE-NPM-MARKS")...)
|
||||
creator.AddLine("", nil, clearSpecs...)
|
||||
|
||||
creator.AddLine("", nil, util.IptablesAppendFlag, util.IptablesAzureAcceptChain, util.IptablesJumpFlag, util.IptablesAccept)
|
||||
|
||||
creator.AddLine("", nil, util.IptablesRestoreCommit)
|
||||
return creator
|
||||
}
|
||||
|
|
|
@ -1,27 +1,30 @@
|
|||
package policies
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/Azure/azure-container-networking/npm/pkg/dataplane/ipsets"
|
||||
"github.com/Azure/azure-container-networking/npm/util"
|
||||
networkingv1 "k8s.io/api/networking/v1"
|
||||
)
|
||||
|
||||
type NPMNetworkPolicy struct {
|
||||
// Netpol Key
|
||||
Name string
|
||||
NameSpace string
|
||||
// TODO(jungukcho)
|
||||
// ipsets.IPSetMetadata is common data in both PodSelectorIPSets and PodSelectorList.
|
||||
// So, they can be one datastructure holding all information without redundancy.
|
||||
// PodSelectorIPSets holds all the IPSets generated from Pod Selector
|
||||
PodSelectorIPSets []*ipsets.TranslatedIPSet
|
||||
// PodSelectorList holds target pod information to avoid duplicatoin in SrcList and DstList fields in ACLs
|
||||
PodSelectorList []SetInfo
|
||||
// RuleIPSets holds all IPSets generated from policy's rules
|
||||
// and not from pod selector IPSets
|
||||
//
|
||||
RuleIPSets []*ipsets.TranslatedIPSet
|
||||
ACLs []*ACLPolicy
|
||||
// podIP is key and endpoint ID as value
|
||||
// Will be populated by dataplane and policy manager
|
||||
PodEndpoints map[string]string
|
||||
RawNP *networkingv1.NetworkPolicy
|
||||
}
|
||||
|
||||
// ACLPolicy equivalent to a single iptable rule in linux
|
||||
|
@ -42,14 +45,31 @@ type ACLPolicy struct {
|
|||
Target Verdict
|
||||
// Direction defines the flow of traffic
|
||||
Direction Direction
|
||||
// SrcPorts holds the source port information
|
||||
SrcPorts []Ports
|
||||
// DstPorts holds the destination port information
|
||||
DstPorts []Ports
|
||||
// TODO(jungukcho): It may be better to use pointer to differentiate default value.
|
||||
DstPorts Ports
|
||||
// Protocol is the value of traffic protocol
|
||||
Protocol Protocol
|
||||
}
|
||||
|
||||
const policyIDPrefix = "azure-acl"
|
||||
|
||||
// aclPolicyID returns azure-acl-<network policy namespace>-<network policy name> format
|
||||
// to differentiate ACLs among different network policies,
|
||||
// but aclPolicy in the same network policy has the same aclPolicyID.
|
||||
func aclPolicyID(policyNS, policyName string) string {
|
||||
return fmt.Sprintf("%s-%s-%s", policyIDPrefix, policyNS, policyName)
|
||||
}
|
||||
|
||||
func NewACLPolicy(policyNS, policyName string, target Verdict, direction Direction) *ACLPolicy {
|
||||
acl := &ACLPolicy{
|
||||
PolicyID: aclPolicyID(policyNS, policyName),
|
||||
Target: target,
|
||||
Direction: direction,
|
||||
}
|
||||
return acl
|
||||
}
|
||||
|
||||
func (aclPolicy *ACLPolicy) hasKnownDirection() bool {
|
||||
return aclPolicy.Direction == Ingress ||
|
||||
aclPolicy.Direction == Egress ||
|
||||
|
@ -77,16 +97,19 @@ func (aclPolicy *ACLPolicy) hasKnownTarget() bool {
|
|||
}
|
||||
|
||||
func (aclPolicy *ACLPolicy) satisifiesPortAndProtocolConstraints() bool {
|
||||
return aclPolicy.Protocol != AnyProtocol ||
|
||||
(len(aclPolicy.SrcPorts) == 0 && len(aclPolicy.DstPorts) == 0)
|
||||
// TODO(jungukcho): need to check second condition
|
||||
return (aclPolicy.Protocol != AnyProtocol) || (aclPolicy.DstPorts.Port == 0 && aclPolicy.DstPorts.EndPort == 0)
|
||||
}
|
||||
|
||||
// SetInfo helps capture additional details in a matchSet
|
||||
// example match set in linux:
|
||||
// ! azure-npm-123 src,src
|
||||
// "!" this indicates a negative match of an IPset for src,src
|
||||
// Included flag captures the negative or positive match
|
||||
// MatchType captures match flags
|
||||
// SetInfo helps capture additional details in a matchSet.
|
||||
// Included flag captures the negative or positive match.
|
||||
// Included is true when match set does not have "!".
|
||||
// Included is false when match set have "!".
|
||||
// MatchType captures match direction flags.
|
||||
// For example match set in linux:
|
||||
// ! azure-npm-123 src
|
||||
// "!" this indicates a negative match (Included is false) of an azure-npm-123
|
||||
// MatchType is "src"
|
||||
type SetInfo struct {
|
||||
IPSet *ipsets.IPSetMetadata
|
||||
Included bool
|
||||
|
@ -97,6 +120,15 @@ type SetInfo struct {
|
|||
// To specify one port, set Port and EndPort to the same value.
|
||||
// uint16 is used since there are 2^16 - 1 TCP/UDP ports (0 is invalid)
|
||||
// and 2^16 SCTP ports. ICMP is connectionless and doesn't use ports.
|
||||
// NewSetInfo creates SetInfo.
|
||||
func NewSetInfo(name string, setType ipsets.SetType, included bool, matchType MatchType) SetInfo {
|
||||
return SetInfo{
|
||||
IPSet: ipsets.NewIPSetMetadata(name, setType),
|
||||
Included: included,
|
||||
MatchType: matchType,
|
||||
}
|
||||
}
|
||||
|
||||
type Ports struct {
|
||||
Port int32
|
||||
EndPort int32
|
||||
|
|
|
@ -96,15 +96,9 @@ func normalizePolicy(networkPolicy *NPMNetworkPolicy) {
|
|||
if aclPolicy.Protocol == "" {
|
||||
aclPolicy.Protocol = AnyProtocol
|
||||
}
|
||||
for _, portRange := range aclPolicy.SrcPorts {
|
||||
if portRange.EndPort == 0 {
|
||||
portRange.EndPort = portRange.Port
|
||||
}
|
||||
}
|
||||
for _, portRange := range aclPolicy.DstPorts {
|
||||
if portRange.EndPort == 0 {
|
||||
portRange.EndPort = portRange.Port
|
||||
}
|
||||
|
||||
if aclPolicy.DstPorts.EndPort == 0 {
|
||||
aclPolicy.DstPorts.EndPort = aclPolicy.DstPorts.Port
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -128,16 +122,11 @@ func checkForErrors(networkPolicy *NPMNetworkPolicy) error {
|
|||
string(aclPolicy.Protocol),
|
||||
))
|
||||
}
|
||||
for _, portRange := range aclPolicy.DstPorts {
|
||||
if !portRange.isValidRange() {
|
||||
return npmerrors.SimpleError(fmt.Sprintf("ACL policy %s has invalid port range in DstPorts (start: %d, end: %d)", aclPolicy.PolicyID, portRange.Port, portRange.EndPort))
|
||||
}
|
||||
}
|
||||
for _, portRange := range aclPolicy.DstPorts {
|
||||
if !portRange.isValidRange() {
|
||||
return npmerrors.SimpleError(fmt.Sprintf("ACL policy %s has invalid port range in SrcPorts (start: %d, end: %d)", aclPolicy.PolicyID, portRange.Port, portRange.EndPort))
|
||||
}
|
||||
|
||||
if !aclPolicy.DstPorts.isValidRange() {
|
||||
return npmerrors.SimpleError(fmt.Sprintf("ACL policy %s has invalid port range in DstPorts (start: %d, end: %d)", aclPolicy.PolicyID, aclPolicy.DstPorts.Port, aclPolicy.DstPorts.EndPort))
|
||||
}
|
||||
|
||||
for _, setInfo := range aclPolicy.SrcList {
|
||||
if !setInfo.hasKnownMatchType() {
|
||||
return npmerrors.SimpleError(fmt.Sprintf("ACL policy %s has set %s in SrcList with unknown Match Type", aclPolicy.PolicyID, setInfo.IPSet.Name))
|
||||
|
|
|
@ -2,7 +2,6 @@ package policies
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/Azure/azure-container-networking/log"
|
||||
"github.com/Azure/azure-container-networking/npm/pkg/dataplane/ioutil"
|
||||
|
@ -114,10 +113,7 @@ func (pMgr *PolicyManager) getNewCreatorWithChains(chainNames []string) *ioutil.
|
|||
|
||||
// will make a similar func for on update eventually
|
||||
func (pMgr *PolicyManager) deleteOldJumpRulesOnRemove(policy *NPMNetworkPolicy) error {
|
||||
fmt.Println(policy.ACLs[0])
|
||||
|
||||
shouldDeleteIngress, shouldDeleteEgress := policy.hasIngressAndEgress()
|
||||
fmt.Println(shouldDeleteIngress, shouldDeleteEgress)
|
||||
if shouldDeleteIngress {
|
||||
if err := pMgr.deleteJumpRule(policy, true); err != nil {
|
||||
return err
|
||||
|
@ -224,8 +220,7 @@ func writeNetworkPolicyRules(creator *ioutil.FileCreator, networkPolicy *NPMNetw
|
|||
func getIPTablesRuleSpecs(aclPolicy *ACLPolicy) []string {
|
||||
specs := make([]string, 0)
|
||||
specs = append(specs, util.IptablesProtFlag, string(aclPolicy.Protocol)) // NOTE: protocol must be ALL instead of nil
|
||||
specs = append(specs, getPortSpecs(aclPolicy.SrcPorts, false)...)
|
||||
specs = append(specs, getPortSpecs(aclPolicy.DstPorts, true)...)
|
||||
specs = append(specs, getPortSpecs([]Ports{aclPolicy.DstPorts})...)
|
||||
specs = append(specs, getMatchSetSpecsFromSetInfo(aclPolicy.SrcList)...)
|
||||
specs = append(specs, getMatchSetSpecsFromSetInfo(aclPolicy.DstList)...)
|
||||
if aclPolicy.Comment != "" {
|
||||
|
@ -234,28 +229,18 @@ func getIPTablesRuleSpecs(aclPolicy *ACLPolicy) []string {
|
|||
return specs
|
||||
}
|
||||
|
||||
func getPortSpecs(portRanges []Ports, isDst bool) []string {
|
||||
if len(portRanges) == 0 {
|
||||
func getPortSpecs(portRanges []Ports) []string {
|
||||
// TODO(jungukcho): do not need to take slices since it can only have one dst port
|
||||
if len(portRanges) != 1 {
|
||||
return []string{}
|
||||
}
|
||||
if len(portRanges) == 1 {
|
||||
portFlag := util.IptablesSrcPortFlag
|
||||
if isDst {
|
||||
portFlag = util.IptablesDstPortFlag
|
||||
}
|
||||
return []string{portFlag, portRanges[0].toIPTablesString()}
|
||||
|
||||
// TODO(jungukcho): temporary solution and need to fix it.
|
||||
if portRanges[0].Port == 0 && portRanges[0].EndPort == 0 {
|
||||
return []string{}
|
||||
}
|
||||
|
||||
portRangeStrings := make([]string, 0)
|
||||
for _, portRange := range portRanges {
|
||||
portRangeStrings = append(portRangeStrings, portRange.toIPTablesString())
|
||||
}
|
||||
portFlag := util.IptablesMultiSrcPortFlag
|
||||
if isDst {
|
||||
portFlag = util.IptablesMultiDstPortFlag
|
||||
}
|
||||
specs := []string{util.IptablesModuleFlag, util.IptablesMultiportFlag, portFlag}
|
||||
return append(specs, strings.Join(portRangeStrings, ","))
|
||||
return []string{util.IptablesDstPortFlag, portRanges[0].toIPTablesString()}
|
||||
}
|
||||
|
||||
func getMatchSetSpecsForNetworkPolicy(networkPolicy *NPMNetworkPolicy, matchType MatchType) []string {
|
||||
|
|
|
@ -24,11 +24,11 @@ var (
|
|||
testPolicy3EgressJump = fmt.Sprintf("-j %s", testPolicy3EgressChain)
|
||||
|
||||
testACLRule1 = fmt.Sprintf(
|
||||
"-j MARK --set-mark 0x4000 -p tcp --sport 144:255 -m multiport --dports 222:333,456 -m set --match-set %s src -m set ! --match-set %s dst -m comment --comment comment1",
|
||||
"-j MARK --set-mark 0x4000 -p tcp --dport 222:333 -m set --match-set %s src -m set ! --match-set %s dst -m comment --comment comment1",
|
||||
ipsets.TestCIDRSet.HashedName,
|
||||
ipsets.TestKeyPodSet.HashedName,
|
||||
)
|
||||
testACLRule2 = fmt.Sprintf("-j AZURE-NPM-EGRESS -p udp --sport 144 -m set --match-set %s src -m comment --comment comment2", ipsets.TestCIDRSet.HashedName)
|
||||
testACLRule2 = fmt.Sprintf("-j AZURE-NPM-EGRESS -p udp -m set --match-set %s src -m comment --comment comment2", ipsets.TestCIDRSet.HashedName)
|
||||
testACLRule3 = fmt.Sprintf("-j MARK --set-mark 0x5000 -p udp --dport 144 -m set --match-set %s src -m comment --comment comment3", ipsets.TestCIDRSet.HashedName)
|
||||
testACLRule4 = fmt.Sprintf("-j AZURE-NPM-ACCEPT -p all -m set --match-set %s src -m comment --comment comment4", ipsets.TestCIDRSet.HashedName)
|
||||
)
|
||||
|
|
|
@ -50,12 +50,8 @@ var (
|
|||
},
|
||||
Target: Dropped,
|
||||
Direction: Ingress,
|
||||
SrcPorts: []Ports{
|
||||
{144, 255},
|
||||
},
|
||||
DstPorts: []Ports{
|
||||
{222, 333},
|
||||
{456, 456},
|
||||
DstPorts: Ports{
|
||||
222, 333,
|
||||
},
|
||||
Protocol: TCP,
|
||||
},
|
||||
|
@ -71,9 +67,6 @@ var (
|
|||
},
|
||||
Target: Allowed,
|
||||
Direction: Ingress,
|
||||
SrcPorts: []Ports{
|
||||
{144, 144},
|
||||
},
|
||||
Protocol: UDP,
|
||||
},
|
||||
{
|
||||
|
@ -88,8 +81,8 @@ var (
|
|||
},
|
||||
Target: Dropped,
|
||||
Direction: Egress,
|
||||
DstPorts: []Ports{
|
||||
{144, 144},
|
||||
DstPorts: Ports{
|
||||
144, 144,
|
||||
},
|
||||
Protocol: UDP,
|
||||
},
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: allow-all-to-in-testnamespace-for-ingress
|
||||
namespace: testnamespace
|
||||
spec:
|
||||
policyTypes:
|
||||
- Ingress
|
||||
podSelector: {}
|
||||
ingress:
|
||||
- {}
|
|
@ -0,0 +1,10 @@
|
|||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: deny-all-ingress
|
||||
namespace: testnamespace
|
||||
spec:
|
||||
podSelector: {}
|
||||
policyTypes:
|
||||
- Ingress
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: only-port
|
||||
namespace: default
|
||||
spec:
|
||||
ingress:
|
||||
- ports:
|
||||
# or
|
||||
- port: 80
|
||||
protocol: TCP
|
||||
- port: 100
|
||||
protocol: UDP
|
||||
podSelector:
|
||||
matchLabels:
|
||||
app: server
|
||||
policyTypes:
|
||||
- Ingress
|
|
@ -47,6 +47,7 @@ const (
|
|||
IptablesMark string = "MARK"
|
||||
IptablesSrcFlag string = "src"
|
||||
IptablesDstFlag string = "dst"
|
||||
IptablesNamedPortFlag string = "dst,dst"
|
||||
IptablesNotFlag string = "!"
|
||||
IptablesProtFlag string = "-p"
|
||||
IptablesSFlag string = "-s"
|
||||
|
@ -64,8 +65,6 @@ const (
|
|||
IptablesCtstateModuleFlag string = "conntrack" // state module is obsolete: https://unix.stackexchange.com/questions/108169/what-is-the-difference-between-m-conntrack-ctstate-and-m-state-state
|
||||
IptablesCtstateFlag string = "--ctstate"
|
||||
IptablesMultiportFlag string = "multiport"
|
||||
IptablesMultiDstPortFlag string = "--dports"
|
||||
IptablesMultiSrcPortFlag string = "--sports"
|
||||
IptablesRelatedState string = "RELATED"
|
||||
IptablesEstablishedState string = "ESTABLISHED"
|
||||
IptablesNewState string = "NEW"
|
||||
|
|
Загрузка…
Ссылка в новой задаче