Skip to content
This repository has been archived by the owner on Oct 21, 2022. It is now read-only.

Commit

Permalink
Enable karydia-default-network-policy for enhanced security (#164)
Browse files Browse the repository at this point in the history
Level 1 Network Policy / karydia-default-network-policy added security for the following aspects:
- block access to host network (AWS only)
- block access to meta data services (AWS, GCP, Azure and Alibaba Cloud)
  • Loading branch information
Tobias1501 authored and ionysos committed Jul 29, 2019
1 parent 9ea81b3 commit e12dd21
Show file tree
Hide file tree
Showing 7 changed files with 193 additions and 4 deletions.
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,12 @@ make e2e-test
```
make test
```

### Debug Karydia

To be able to debug (e.g. Visual Studio Code), change the following line in the Debug configuration:

```
"args": ["--kubeconfig","<PATH>/.kube/config"]
```

6 changes: 6 additions & 0 deletions docs/features.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@ not running will not be updated when karydia starts.

The network policy is expected to be found under `.data.policy` in the configmap.

The current network policy called `karydia-default-network-policy` has two security measures:
1. block access to host network (AWS only)
2. block access to Meta Data Services (AWS, GCP, Azure, Alibaba Cloud)

Note: The network policy is still quite open. It uses a blacklisting approach and does not block Internet access (Egress).

## Karydia Admission

Karydia Admission (`--enable-karydia-admission`) offers features with the goal of a secure-by-default cluster setup. You can enable/disable and configure this feature in the `install/charts/values.yaml` file.
Expand Down
11 changes: 11 additions & 0 deletions install/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,17 @@ karydia can be installed as a webhook into any Kubernetes cluster.

The installation processes uses [Helm](https://github.com/helm/helm) to get karydia up and running and is split up into two parts.

## Clone Respository

Clone the repository and install the dependencies:

```
cd ~
go install github.com/karydia/karydia
cd ~/go/src/github.com/karydia/karydia
go install ./...
```

## Prepare Helm and Tiller
First, create a Helm service account and initiate Tiller on the cluster. Thus, run:
```
Expand Down
4 changes: 2 additions & 2 deletions install/charts/templates/configmap.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,5 @@ data:
{{- include "create-karydia-certificate.sh.tpl" . | indent 4}}
create-karydia-tls-secret.sh: |-
{{- include "create-karydia-tls-secret.sh.tpl" . | indent 4}}
example-default-network-policy.sh: |-
{{- include "example-default-network-policy.sh.tpl" . | indent 4}}
karydia-default-network-policy.sh: |-
{{- include "karydia-default-network-policy.sh.tpl" . | indent 4}}
2 changes: 1 addition & 1 deletion install/charts/templates/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ spec:
initContainers:
- name: pre-install-{{ .Values.metadata.name }}
image: lachlanevenson/k8s-kubectl
command: ['sh', '-c', 'apk add --update --no-cache openssl && sh /tmp/create-karydia-certificate.sh && sh /tmp/create-karydia-tls-secret.sh && sh /tmp/example-default-network-policy.sh']
command: ['sh', '-c', 'apk add --update --no-cache openssl && sh /tmp/create-karydia-certificate.sh && sh /tmp/create-karydia-tls-secret.sh && sh /tmp/karydia-default-network-policy.sh']
volumeMounts:
- name: workdir
mountPath: "/tmp"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{{ define "example-default-network-policy.sh.tpl" }}
{{ define "karydia-default-network-policy.sh.tpl" }}
#!/bin/bash

# Copyright (C) 2019 SAP SE or an SAP affiliate company. All rights reserved.
Expand Down Expand Up @@ -31,6 +31,14 @@ spec:
podSelector: {}
policyTypes:
- Egress
egress:
- to:
- ipBlock:
cidr: 0.0.0.0/0
except:
- 10.250.0.0/16 # host network (AWS only)
- 169.254.169.254/16 # meta data services (AWS, GCP, Azure)
- 100.100.0.0/16 # meta data services (Alibaba Cloud)
EOF
)

Expand Down
155 changes: 155 additions & 0 deletions tests/e2e/karydia_default_network_policy_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
// Copyright (C) 2019 SAP SE or an SAP affiliate company. All rights reserved.
// This file is licensed under the Apache Software License, v. 2 except as
// noted otherwise in the LICENSE file.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package e2e

import (
"os/exec"
"strings"
"syscall"
"testing"
"time"

corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

const (
Success int = 0
TimeOut int = 1
)

func execCommandAssertExitCode(t *testing.T, command string, expectedExitCode int) {
exitCode := Success

args := strings.Fields(command)
cmd := exec.Command(args[0], args[1:]...)
err := cmd.Run()

if err != nil {
// try to get the exit code
if exitError, ok := err.(*exec.ExitError); ok {
ws := exitError.Sys().(syscall.WaitStatus)
exitCode = ws.ExitStatus()

if exitCode != expectedExitCode {
t.Fatalf("Exit status with unexpected code: %d %s", exitCode, command)
}
} else {
t.Fatalf("Could not get exit code.")
}
} else {
// success, exitCode should be 0 if go is ok
ws := cmd.ProcessState.Sys().(syscall.WaitStatus)
exitCode = ws.ExitStatus()

if exitCode != expectedExitCode {
t.Fatalf("Exit status with unexpected code: %d %s", exitCode, command)
}
}
}

func TestNetworkPolicyLevel1(t *testing.T) {

var namespace *corev1.Namespace
var err error

namespace, err = f.CreateTestNamespace()
if err != nil {
t.Fatalf("failed to create test namespace: %v", err)
}

ns := namespace.ObjectMeta.Name

pod := &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "karydia-network-policy-1",
Namespace: ns,
},
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{
Name: "karydia-e2e-test-container",
Image: "alpine",
Command: []string{"tail", "-f", "/dev/null"},
},
},
},
}

createdPod, err := f.KubeClientset.CoreV1().Pods(ns).Create(pod)
if err != nil {
t.Fatalf("Failed to create: " + err.Error())
}
podName := createdPod.ObjectMeta.Name

timeout := 2 * time.Minute
if err := f.WaitPodRunning(ns, podName, timeout); err != nil {
t.Fatalf("pod never reached state running")
}

// host network (AWS only)
cmd1 := "kubectl exec --namespace=" + ns + " " + podName + " -- wget --spider --timeout 3 10.250.0.0"
execCommandAssertExitCode(t, cmd1, TimeOut)

cmd2 := "kubectl exec --namespace=" + ns + " " + podName + " -- wget --spider --timeout 3 10.250.1.1"
execCommandAssertExitCode(t, cmd2, TimeOut)

cmd3 := "kubectl exec --namespace=" + ns + " " + podName + " -- wget --spider --timeout 3 10.250.50.200"
execCommandAssertExitCode(t, cmd3, TimeOut)

// meta data services (AWS, GCP, Azure)
cmd4 := "kubectl exec --namespace=" + ns + " " + podName + " -- wget --spider --timeout 3 169.254.169.254"
execCommandAssertExitCode(t, cmd4, TimeOut)

cmd5 := "kubectl exec --namespace=" + ns + " " + podName + " -- wget --spider --timeout 3 169.254.0.0"
execCommandAssertExitCode(t, cmd5, TimeOut)

cmd6 := "kubectl exec --namespace=" + ns + " " + podName + " -- wget --spider --timeout 3 169.254.2.2"
execCommandAssertExitCode(t, cmd6, TimeOut)

// meta data services (Alibaba Cloud)
cmd7 := "kubectl exec --namespace=" + ns + " " + podName + " -- wget --spider --timeout 3 100.100.0.0"
execCommandAssertExitCode(t, cmd7, TimeOut)

cmd8 := "kubectl exec --namespace=" + ns + " " + podName + " -- wget --spider --timeout 3 100.100.1.3"
execCommandAssertExitCode(t, cmd8, TimeOut)

cmd9 := "kubectl exec --namespace=" + ns + " " + podName + " -- wget --spider --timeout 3 100.100.60.155"
execCommandAssertExitCode(t, cmd9, TimeOut)

// external traffic with static IPs
// Google DNS
cmd10 := "kubectl exec --namespace=" + ns + " " + podName + " -- wget --spider --timeout 3 https://8.8.8.8"
execCommandAssertExitCode(t, cmd10, Success)

// Cloudflare DNS
cmd11 := "kubectl exec --namespace=" + ns + " " + podName + " -- wget --spider --timeout 3 1.1.1.1"
execCommandAssertExitCode(t, cmd11, Success)

// external traffic with domain names
cmd12 := "kubectl exec --namespace=" + ns + " " + podName + " -- wget --spider --timeout 3 www.google.de"
execCommandAssertExitCode(t, cmd12, Success)

cmd13 := "kubectl exec --namespace=" + ns + " " + podName + " -- wget --spider --timeout 3 www.sap.com"
execCommandAssertExitCode(t, cmd13, Success)

err = f.KubeClientset.CoreV1().Pods(ns).Delete(createdPod.ObjectMeta.Name, &metav1.DeleteOptions{})
if err != nil {
t.Fatalf("pod could not be deleted")
}

}

0 comments on commit e12dd21

Please sign in to comment.