Skip to content

Commit

Permalink
Start to flesh out config and enablement
Browse files Browse the repository at this point in the history
  • Loading branch information
tylerflint committed Nov 9, 2023
1 parent 311d16e commit 7aa7336
Show file tree
Hide file tree
Showing 9 changed files with 167 additions and 21 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ kind-rollout: ## Creates a new rollout with the newest image

.PHONY: kind-cert-manager
kind-cert-manager: ## Installs cert manager onto the kind cluster
@($(HELM) repo list | grep -qw "jetstack" || \
($(HELM) repo list | grep -qw "jetstack" || \
($(HELM) repo add jetstack https://charts.jetstack.io && $(HELM) repo update)) && \
($(KUBECTL) get namespaces | grep -qw "cert-manager" || \
$(HELM) install \
Expand Down
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,21 @@ todo

__Option 1:__ Namespace label

```
kubectl label namespace <namespace> qpoint-egress=enabled
```

__Option 2:__ Pod annotation

```
apiVersion: v1
kind: Pod
metadata:
name: hello-world
annotations:
qpoint.io/egress: enabled
```

## Local Dev

Bootstrap dev cluster (uses KinD) with live-reloading
Expand Down
60 changes: 60 additions & 0 deletions api/v1/assets/build-ca.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#!/usr/bin/env sh

# certificate authority bundles for common distributions
bundles="
/etc/ssl/certs/ca-certificates.crt \
/etc/pki/tls/certs/ca-bundle.crt \
/etc/ssl/ca-bundle.pem \
/etc/pki/tls/cacert.pem \
/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem \
/etc/ssl/cert.pem
"

# qpoint ca
qpoint_ca="/mnt/ca/qpoint.pem"

# tls config destination
destination="/mnt/tls"

# initialize a flag to check if config was copied
config_copied="no"

# convert string to an array-like structure
set -- $bundles

# iterate over the possible bundles
for bundle; do
if [ -f "$bundle" ]; then
echo "Found ca bundle: ${bundle}"

# extract the directly/file from the bundle
directory=$(dirname "$bundle")
file=$(basename "$bundle")

# copy the contents of the bundle into the shared mount
echo "Copying contents of $directory to $destination"
cp -R "$directory"/* "$destination"

# append the qpoint root ca
cat "$qpoint_ca" >> "$destination/$file"

# leave the breadcrumb
config_copied="yes"

# stop after the first found bundle
break
fi
done

# we didn't find a matching config, likely there is no openssl installed
#
# in this case our approach is to just add our ca to all of the bundles
# for the potential distributions
if [ "$config_copied" = "no" ]; then
echo "No config copied, creating new CA bundles."
set -- $bundles
for bundle; do
file=$(basename "$bundle")
cat "$qpoint_ca" > "$destination/$file"
done
fi
5 changes: 5 additions & 0 deletions api/v1/ca.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
package v1

import (
_ "embed"

corev1 "k8s.io/api/core/v1"
)

//go:embed assets/build-ca.sh
var buildCaScript string

func MutateCaInjection(pod *corev1.Pod, config *Config) error {
return nil
}
63 changes: 51 additions & 12 deletions api/v1/config.go
Original file line number Diff line number Diff line change
@@ -1,27 +1,66 @@
package v1

import (
"context"
"fmt"

corev1 "k8s.io/api/core/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
)

var (
defaultAnnotations = map[string]string{
"key1": "value1",
"key2": "value2",
}
)

type Config struct {
Enabled bool
InjectCa bool
Namespace string
Enabled bool
InjectCa bool

apiClient client.Client
apiClient client.Client
annotations map[string]string
}

func InitConfig(apiClient client.Client, namespace string, pod *corev1.Pod) (*Config, error) {
// start with a default config
config := &Config{
Enabled: false,
InjectCa: true,
apiClient: apiClient,
func (c *Config) Init(ctx context.Context, pod *corev1.Pod) error {
// check to see if an annotation is set on the pod to enable egress
egress, exists := pod.Annotations["qpoint.io/egress"]
if exists && egress == "enabled" {
c.Enabled = true
}

// if we're not enabled yet, let's check the namespace
if !c.Enabled {
namespace := &corev1.Namespace{}
if err := c.apiClient.Get(ctx, client.ObjectKey{Name: c.Namespace}, namespace); err != nil {
return fmt.Errorf("fetching namespace '%s' from the api: %w", c.Namespace, err)
}

// if the namespace is labeled, then we enable
if namespace.Labels["qpoint-egress"] == "enabled" {
c.Enabled = true
}
}

// if we're enabled
if c.Enabled {

// let's apply the default annotations to the pod (for transparency to the admin)
for key, value := range defaultAnnotations {
if _, exists := pod.Annotations[key]; !exists {
pod.Annotations[key] = value
}
}

// and store a direct reference to the annotations for config
c.annotations = pod.Annotations
}

// enable for time-being
config.Enabled = true
return nil
}

return config, nil
func (c *Config) Get(key string) string {
return c.annotations[fmt.Sprintf("qpoint.io/%s", key)]
}
16 changes: 16 additions & 0 deletions api/v1/egress.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,21 @@ import (
)

func MutateEgress(pod *corev1.Pod, config *Config) error {
// create an init container
initContainer := corev1.Container{
Name: "qtap-init",
Image: "us-docker.pkg.dev/qpoint-edge/public/kubernetes-qtap-init",
Env: []corev1.EnvVar{},
SecurityContext: &corev1.SecurityContext{
Capabilities: &corev1.Capabilities{
Add: []corev1.Capability{"NET_ADMIN"},
},
},
}

// append to the list
pod.Spec.InitContainers = append(pod.Spec.InitContainers, initContainer)

// gtg
return nil
}
24 changes: 17 additions & 7 deletions api/v1/webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,6 @@ import (
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
)

var (
webhookLog = ctrl.Log.WithName("pod.v1.admission.webhook")
)

type Webhook struct {
Development bool
ApiClient client.Client
Expand All @@ -25,22 +21,34 @@ type Webhook struct {
// +kubebuilder:webhook:path=/mutate-v1-pod,mutating=true,failurePolicy=fail,groups="",resources=pods,verbs=create;update,versions=v1,name=mpod.kb.io,sideEffects=None,admissionReviewVersions=v1

func (w *Webhook) Handle(ctx context.Context, req admission.Request) admission.Response {
// create a logger
webhookLog := ctrl.Log.WithName(fmt.Sprintf("pod.v1.admission.webhook[%s]", req.UID))

pod := &corev1.Pod{}
err := w.Decoder.Decode(req, pod)
if err != nil {
return admission.Errored(http.StatusBadRequest, err)
}

webhookLog.Info(fmt.Sprintf("Pod mutation requested: %s", req.UID))
webhookLog.Info("Pod mutation requested")

// initilize a config with defaults
config := &Config{
Namespace: req.Namespace,
Enabled: false,
InjectCa: true,
apiClient: w.ApiClient,
}

// initialize config for this pod
config, err := InitConfig(w.ApiClient, req.Namespace, pod)
if err != nil {
if err := config.Init(ctx, pod); err != nil {
webhookLog.Error(err, "failed to initialize config for pod")
return admission.Errored(http.StatusInternalServerError, err)
}

if config.Enabled {
webhookLog.Info("Qpoint egress enabled, mutating...")

// if w.Development {
// fmt.Println("Before: ")
// jsonBytes, _ := json.MarshalIndent(pod, "", " ")
Expand All @@ -65,6 +73,8 @@ func (w *Webhook) Handle(ctx context.Context, req admission.Request) admission.R
// jsonBytes, _ := json.MarshalIndent(pod, "", " ")
// fmt.Println(string(jsonBytes))
// }
} else {
webhookLog.Info("Qpoint egress not enabled, ignoring...")
}

marshaledPod, err := json.Marshal(pod)
Expand Down
3 changes: 3 additions & 0 deletions config/rbac/role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,6 @@ rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["namespaces"]
verbs: ["get", "list", "watch"]
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module github.com/qpoint-io/kubernetes-qtap-operator
go 1.20

require (
k8s.io/api v0.28.3
k8s.io/apimachinery v0.28.3
k8s.io/client-go v0.28.3
sigs.k8s.io/controller-runtime v0.16.3
Expand Down Expand Up @@ -56,7 +57,6 @@ require (
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/api v0.28.3 // indirect
k8s.io/apiextensions-apiserver v0.28.3 // indirect
k8s.io/component-base v0.28.3 // indirect
k8s.io/klog/v2 v2.100.1 // indirect
Expand Down

0 comments on commit 7aa7336

Please sign in to comment.