Skip to content

Commit 0169474

Browse files
authored
Sync PA security policy's SourceAddress from Namespace annotation (#14)
1 parent 80cb924 commit 0169474

File tree

9 files changed

+160
-13
lines changed

9 files changed

+160
-13
lines changed

Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
VERSION_MAJOR ?= 0
2-
VERSION_MINOR ?= 6
3-
VERSION_BUILD ?= 5
2+
VERSION_MINOR ?= 7
3+
VERSION_BUILD ?= 0
44
VERSION ?= v$(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_BUILD)
55

66
GOOS ?= $(shell go env GOOS)

deploy/deployment.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ spec:
2222
serviceAccountName: pa-svc-syncker
2323
containers:
2424
- name: pa-svc-syncker
25-
image: inwinstack/pa-svc-syncker:v0.6.5
25+
image: inwinstack/pa-svc-syncker:v0.7.0
2626
args:
2727
- --v=2
2828
- --logtostderr=true

pkg/constants/constants.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,6 @@ const (
2929
AnnKeyPublicIP = "inwinstack.com/allocated-public-ip"
3030
// AnnKeyServiceRefresh set in Service to refresh the annotations
3131
AnnKeyServiceRefresh = "inwinstack.com/service-refresh"
32+
// AnnKeyWhiteListAddresses is the key of annotations for the whitelist
33+
AnnKeyWhiteListAddresses = "inwinstack.com/whitelist-addresses"
3234
)

pkg/k8sutil/k8sutil.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ package k8sutil
1818

1919
import (
2020
"github.com/inwinstack/pa-svc-syncker/pkg/constants"
21-
"k8s.io/api/core/v1"
21+
v1 "k8s.io/api/core/v1"
2222
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2323
"k8s.io/client-go/kubernetes"
2424
"k8s.io/client-go/rest"

pkg/k8sutil/security.go

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ package k8sutil
1919
import (
2020
inwinv1 "github.com/inwinstack/blended/apis/inwinstack/v1"
2121
clientset "github.com/inwinstack/blended/client/clientset/versioned"
22-
"k8s.io/api/core/v1"
22+
v1 "k8s.io/api/core/v1"
2323
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2424
)
2525

@@ -30,6 +30,7 @@ type SecurityParameter struct {
3030
Group string
3131
Services []string
3232
DestinationZones []string
33+
SourceAddresses []string
3334
}
3435

3536
func newSecurity(para *SecurityParameter, svc *v1.Service) *inwinv1.Security {
@@ -40,7 +41,7 @@ func newSecurity(para *SecurityParameter, svc *v1.Service) *inwinv1.Security {
4041
},
4142
Spec: inwinv1.SecuritySpec{
4243
SourceZones: []string{"untrust"},
43-
SourceAddresses: []string{"any"},
44+
SourceAddresses: para.SourceAddresses,
4445
SourceUsers: []string{"any"},
4546
HipProfiles: []string{"any"},
4647
DestinationZones: para.DestinationZones,
@@ -74,3 +75,18 @@ func CreateSecurity(c clientset.Interface, para *SecurityParameter, svc *v1.Serv
7475
func DeleteSecurity(c clientset.Interface, name, namespace string) error {
7576
return c.InwinstackV1().Securities(namespace).Delete(name, nil)
7677
}
78+
79+
func UpdateSecuritiesSourceIPs(c clientset.Interface, namespace string, addrs []string) error {
80+
secs, err := c.InwinstackV1().Securities(namespace).List(metav1.ListOptions{})
81+
if err != nil {
82+
return err
83+
}
84+
85+
for _, sec := range secs.Items {
86+
sec.Spec.SourceAddresses = addrs
87+
if _, err := c.InwinstackV1().Securities(namespace).Update(&sec); err != nil {
88+
return err
89+
}
90+
}
91+
return nil
92+
}
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
/*
2+
Copyright © 2018 inwinSTACK.inc
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package namespace
18+
19+
import (
20+
"reflect"
21+
"strings"
22+
23+
"github.com/golang/glog"
24+
clientset "github.com/inwinstack/blended/client/clientset/versioned"
25+
opkit "github.com/inwinstack/operator-kit"
26+
"github.com/inwinstack/pa-svc-syncker/pkg/config"
27+
"github.com/inwinstack/pa-svc-syncker/pkg/constants"
28+
"github.com/inwinstack/pa-svc-syncker/pkg/k8sutil"
29+
slice "github.com/thoas/go-funk"
30+
v1 "k8s.io/api/core/v1"
31+
"k8s.io/client-go/tools/cache"
32+
)
33+
34+
var Resource = opkit.CustomResource{
35+
Name: "namespace",
36+
Plural: "namespaces",
37+
Version: "v1",
38+
Kind: reflect.TypeOf(v1.Namespace{}).Name(),
39+
}
40+
41+
type NamespaceController struct {
42+
ctx *opkit.Context
43+
client clientset.Interface
44+
cfg *config.OperatorConfig
45+
}
46+
47+
func NewController(ctx *opkit.Context, client clientset.Interface, cfg *config.OperatorConfig) *NamespaceController {
48+
return &NamespaceController{ctx: ctx, client: client, cfg: cfg}
49+
}
50+
51+
func (c *NamespaceController) StartWatch(namespace string, stopCh chan struct{}) error {
52+
resourceHandlerFuncs := cache.ResourceEventHandlerFuncs{
53+
AddFunc: c.onAdd,
54+
UpdateFunc: c.onUpdate,
55+
}
56+
57+
glog.Info("Start watching service resources.")
58+
watcher := opkit.NewWatcher(Resource, namespace, resourceHandlerFuncs, c.ctx.Clientset.CoreV1().RESTClient())
59+
go watcher.Watch(&v1.Namespace{}, stopCh)
60+
return nil
61+
}
62+
63+
func (c *NamespaceController) onAdd(obj interface{}) {
64+
ns := obj.(*v1.Namespace).DeepCopy()
65+
glog.V(2).Infof("Received add on %s namespace.", ns.Name)
66+
67+
if ns.Status.Phase == v1.NamespaceActive {
68+
if err := c.updateSecurityPolicies(ns); err != nil {
69+
glog.Errorf("Failed to add sources addresss to all policies on %s namespace.: %+v.", ns.Name, err)
70+
}
71+
}
72+
}
73+
74+
func (c *NamespaceController) onUpdate(oldObj, newObj interface{}) {
75+
ns := newObj.(*v1.Namespace).DeepCopy()
76+
glog.V(2).Infof("Received update on %s namespace.", ns.Name)
77+
78+
if ns.Status.Phase == v1.NamespaceActive {
79+
if err := c.updateSecurityPolicies(ns); err != nil {
80+
glog.Errorf("Failed to add sources addresss to all policies on %s namespace.: %+v.", ns.Name, err)
81+
}
82+
}
83+
}
84+
85+
func (c *NamespaceController) updateSecurityPolicies(ns *v1.Namespace) error {
86+
if slice.Contains(c.cfg.IgnoreNamespaces, ns.Name) {
87+
return nil
88+
}
89+
90+
addrs := []string{"any"}
91+
if value, ok := ns.Annotations[constants.AnnKeyWhiteListAddresses]; ok {
92+
addrString := strings.TrimSpace(value)
93+
if len(addrString) > 0 {
94+
addrs = strings.Split(addrString, ",")
95+
}
96+
}
97+
if err := k8sutil.UpdateSecuritiesSourceIPs(c.client, ns.Name, addrs); err != nil {
98+
return err
99+
}
100+
return nil
101+
}

pkg/operator/operator.go

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,9 @@ import (
2828
opkit "github.com/inwinstack/operator-kit"
2929
"github.com/inwinstack/pa-svc-syncker/pkg/config"
3030
"github.com/inwinstack/pa-svc-syncker/pkg/k8sutil"
31+
"github.com/inwinstack/pa-svc-syncker/pkg/operator/namespace"
3132
"github.com/inwinstack/pa-svc-syncker/pkg/operator/service"
32-
"k8s.io/api/core/v1"
33+
v1 "k8s.io/api/core/v1"
3334
apiextensionsclientset "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
3435
"k8s.io/client-go/kubernetes"
3536
)
@@ -41,9 +42,10 @@ const (
4142
)
4243

4344
type Operator struct {
44-
ctx *opkit.Context
45-
conf *config.OperatorConfig
46-
service *service.ServiceController
45+
ctx *opkit.Context
46+
conf *config.OperatorConfig
47+
service *service.ServiceController
48+
namespace *namespace.NamespaceController
4749
}
4850

4951
func NewMainOperator(conf *config.OperatorConfig) *Operator {
@@ -57,6 +59,7 @@ func (o *Operator) Initialize() error {
5759
}
5860

5961
o.service = service.NewController(ctx, clientset, o.conf)
62+
o.namespace = namespace.NewController(ctx, clientset, o.conf)
6063
o.ctx = ctx
6164
return nil
6265
}
@@ -100,6 +103,7 @@ func (o *Operator) Run() error {
100103

101104
// start watching the resources
102105
o.service.StartWatch(v1.NamespaceAll, stopChan)
106+
o.namespace.StartWatch(v1.NamespaceAll, stopChan)
103107

104108
for {
105109
select {

pkg/operator/service/controller.go

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package service
1919
import (
2020
"fmt"
2121
"reflect"
22+
"strings"
2223

2324
"github.com/golang/glog"
2425
clientset "github.com/inwinstack/blended/client/clientset/versioned"
@@ -28,7 +29,8 @@ import (
2829
"github.com/inwinstack/pa-svc-syncker/pkg/k8sutil"
2930
"github.com/inwinstack/pa-svc-syncker/pkg/util"
3031
slice "github.com/thoas/go-funk"
31-
"k8s.io/api/core/v1"
32+
v1 "k8s.io/api/core/v1"
33+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3234
"k8s.io/apimachinery/pkg/util/uuid"
3335
"k8s.io/client-go/tools/cache"
3436
)
@@ -177,15 +179,24 @@ func (c *ServiceController) syncNAT(svc *v1.Service, addr string) {
177179

178180
// Sync the PA Security policies
179181
func (c *ServiceController) syncSecurity(svc *v1.Service, addr string) {
180-
name := fmt.Sprintf("k8s-%s", addr)
182+
addrs := []string{"any"}
183+
ns, _ := c.ctx.Clientset.CoreV1().Namespaces().Get(svc.Namespace, metav1.GetOptions{})
184+
if value, ok := ns.Annotations[constants.AnnKeyWhiteListAddresses]; ok {
185+
addrString := strings.TrimSpace(value)
186+
if len(addrString) > 0 {
187+
addrs = strings.Split(addrString, ",")
188+
}
189+
}
181190

191+
name := fmt.Sprintf("k8s-%s", addr)
182192
secPara := &k8sutil.SecurityParameter{
183193
Name: name,
184194
Address: addr,
185195
Log: c.conf.LogSettingName,
186196
Group: c.conf.GroupName,
187197
Services: c.conf.Services,
188198
DestinationZones: c.conf.DestinationZones,
199+
SourceAddresses: addrs,
189200
}
190201
if err := k8sutil.CreateSecurity(c.client, secPara, svc); err != nil {
191202
glog.Warningf("Failed to create and update Security resource: %+v.", err)

pkg/operator/service/controller_test.go

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ import (
3131
corefake "k8s.io/client-go/kubernetes/fake"
3232

3333
"github.com/stretchr/testify/assert"
34-
"k8s.io/api/core/v1"
34+
v1 "k8s.io/api/core/v1"
3535
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3636
)
3737

@@ -40,6 +40,19 @@ func TestController(t *testing.T) {
4040
coreClient := corefake.NewSimpleClientset()
4141
extensionsClient := extensionsfake.NewSimpleClientset()
4242

43+
ns := &v1.Namespace{
44+
ObjectMeta: metav1.ObjectMeta{
45+
Name: "default",
46+
Namespace: "",
47+
Annotations: map[string]string{
48+
constants.AnnKeyExternalPool: "internet",
49+
constants.AnnKeyWhiteListAddresses: "172.22.132.99, 172.22.131.0/32",
50+
},
51+
},
52+
}
53+
_, nserr := coreClient.CoreV1().Namespaces().Create(ns)
54+
assert.Nil(t, nserr)
55+
4356
ip := &inwinv1.IP{
4457
ObjectMeta: metav1.ObjectMeta{
4558
Name: "172.11.22.33",

0 commit comments

Comments
 (0)