Skip to content

Commit

Permalink
Default Network Policy for CIS (#254)
Browse files Browse the repository at this point in the history
* initial

Signed-off-by: Brian Downs <[email protected]>

* add namespace annotation map

Signed-off-by: Brian Downs <[email protected]>

* add retry, namespace update

Signed-off-by: Brian Downs <[email protected]>

* update

Signed-off-by: Brian Downs <[email protected]>

* update

Signed-off-by: Brian Downs <[email protected]>

* update

Signed-off-by: Brian Downs <[email protected]>

* update

Signed-off-by: Brian Downs <[email protected]>

* update

Signed-off-by: Brian Downs <[email protected]>

* pr remediations

Signed-off-by: Brian Downs <[email protected]>

* pr remediations

Signed-off-by: Brian Downs <[email protected]>

* move delete logic

Signed-off-by: Brian Downs <[email protected]>
  • Loading branch information
briandowns authored Aug 28, 2020
1 parent f02ba17 commit afb1e8e
Show file tree
Hide file tree
Showing 3 changed files with 151 additions and 4 deletions.
113 changes: 113 additions & 0 deletions pkg/rke2/np.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package rke2

import (
"context"
"fmt"

daemonsConfig "github.com/rancher/k3s/pkg/daemons/config"
"github.com/rancher/spur/cli"
"github.com/sirupsen/logrus"
v1 "k8s.io/api/networking/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/util/retry"
)

const (
namespaceAnnotationNetworkPolicy = "np.rke2.io"

defaultNetworkPolicyName = "default-network-policy"
)

// networkPolicy specifies a base level network policy applied
// to the 3 primary namespace: kube-system, kube-public, and default.
// This policy only allows for intra-namespace traffic.
var networkPolicy = v1.NetworkPolicy{
ObjectMeta: metav1.ObjectMeta{
Name: defaultNetworkPolicyName,
},
Spec: v1.NetworkPolicySpec{
PodSelector: metav1.LabelSelector{}, // empty to match all pods
PolicyTypes: []v1.PolicyType{v1.PolicyTypeIngress},
Ingress: []v1.NetworkPolicyIngressRule{
{
From: []v1.NetworkPolicyPeer{
{
PodSelector: &metav1.LabelSelector{}, // empty to match all pods
},
},
},
},
},
}

// setNetworkPolicy applies the default network policy for the given namespace and updates
// the given namespaces' annotation. First, the namespaces' annotation is checked for existence.
// If the annotation exists, we move on. If the annoation doesnt' exist, we check to see if the
// policy exists. If it does, we delete it, and create the new default policy.
func setNetworkPolicy(ctx context.Context, namespace string, cs *kubernetes.Clientset) error {
ns, err := cs.CoreV1().Namespaces().Get(ctx, namespace, metav1.GetOptions{})
if err != nil {
return fmt.Errorf("networkPolicy: get %s - %w", namespace, err)
}
if ns.Annotations == nil {
ns.Annotations = make(map[string]string)
}
if _, ok := ns.Annotations[namespaceAnnotationNetworkPolicy]; !ok {
if _, err := cs.NetworkingV1().NetworkPolicies(namespace).Get(ctx, defaultNetworkPolicyName, metav1.GetOptions{}); err != nil {
if !apierrors.IsNotFound(err) {
return err
}
}
if err := cs.NetworkingV1().NetworkPolicies(namespace).Delete(ctx, defaultNetworkPolicyName, metav1.DeleteOptions{}); err != nil {
return err
}
if _, err := cs.NetworkingV1().NetworkPolicies(namespace).Create(ctx, &networkPolicy, metav1.CreateOptions{}); err != nil {
return err
}
ns.Annotations[namespaceAnnotationNetworkPolicy] = cisAnnotationValue

if err := retry.RetryOnConflict(retry.DefaultBackoff, func() error {
if _, err := cs.CoreV1().Namespaces().Update(ctx, ns, metav1.UpdateOptions{}); err != nil {
if apierrors.IsConflict(err) {
if err := updateNamespaceRef(ctx, cs, ns); err != nil {
return err
}
}
return err
}
return nil
}); err != nil {
logrus.Fatalf("networkPolicy: update namespace: %s - %s", ns.Name, err.Error())
}
}
return nil
}

// setNetworkPolicies applies a default network policy across the 3 primary namespaces.
func setNetworkPolicies(clx *cli.Context) func(context.Context, daemonsConfig.Control) error {
return func(ctx context.Context, cfg daemonsConfig.Control) error {
logrus.Info("Applying network policies...")
go func() {
<-cfg.Runtime.APIServerReady

cs, err := newClient(cfg.Runtime.KubeConfigAdmin, nil)
if err != nil {
logrus.Fatalf("networkPolicy: new k8s client: %s", err.Error())
}
var namespaces = []string{
metav1.NamespaceSystem,
metav1.NamespaceDefault,
metav1.NamespacePublic,
}
for _, namespace := range namespaces {
if err := setNetworkPolicy(ctx, namespace, cs); err != nil {
logrus.Fatal(err)
}
}
logrus.Info("Applying network policies complete")
}()
return nil
}
}
37 changes: 34 additions & 3 deletions pkg/rke2/psp.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/transport"
"k8s.io/client-go/util/retry"
)

const (
Expand Down Expand Up @@ -324,16 +325,46 @@ func setPSPs(clx *cli.Context) func(context.Context, daemonsConfig.Control) erro
}
}

if _, err := cs.CoreV1().Namespaces().Update(ctx, ns, metav1.UpdateOptions{}); err != nil {
logrus.Fatalf("psp: update namespace annotation: %s", err.Error())
if err := retry.RetryOnConflict(retry.DefaultBackoff, func() error {
if _, err := cs.CoreV1().Namespaces().Update(ctx, ns, metav1.UpdateOptions{}); err != nil {
if apierrors.IsConflict(err) {
if err := updateNamespaceRef(ctx, cs, ns); err != nil {
return err
}
}
return err
}
return nil
}); err != nil {
logrus.Fatalf("psp: update namespace: %s - %s", ns.Name, err.Error())
}

logrus.Info("Applying PSP's complete")
}()
return nil
}
}

// updateNamespaceRef receives a value of type v1.Namespace pointer
// and updates that value to point to a newly retrieve value in
// the event a conflict error is returned.
func updateNamespaceRef(ctx context.Context, cs *kubernetes.Clientset, ns *v1.Namespace) error {
logrus.Info("updating namespace: " + ns.Name)
newNS, err := cs.CoreV1().Namespaces().Get(ctx, ns.Name, metav1.GetOptions{})
if err != nil {
return err
}
if newNS.Annotations == nil {
newNS.Annotations = make(map[string]string, len(ns.Annotations))
}
// copy any annotations that need to be written that
// may not have been written yet.
for k, v := range ns.Annotations {
newNS.Annotations[k] = v
}
*ns = *newNS
return nil
}

type deployFn func(context.Context, *kubernetes.Clientset, interface{}) error

// newClient create a new Kubernetes client from configuration.
Expand Down
5 changes: 4 additions & 1 deletion pkg/rke2/rke2.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,10 @@ func Server(ctx *cli.Context, cfg Config) error {
return err
}

cmds.ServerConfig.StartupHooks = append(cmds.ServerConfig.StartupHooks, setPSPs(ctx))
cmds.ServerConfig.StartupHooks = append(cmds.ServerConfig.StartupHooks,
setPSPs(ctx),
setNetworkPolicies(ctx),
)

return server.Run(ctx)
}
Expand Down

0 comments on commit afb1e8e

Please sign in to comment.