Giter VIP home page Giter VIP logo

k8s-env-injector's Introduction

Kubernetes Mutating Admission Webhook for environment injection

This repo hosts a MutatingAdmissionWebhook that injects environment variables, dns options and node affinity into pod containers prior to persistence of the object. Node affinity is currently limited to RequiredDuringSchedulingIgnoredDuringExecution selector terms.

The image can be used along with several Kubernetes resources to update specific settings on your pods based on a label applied to the namespace of the pod i.e.

  • Apply the label to the namespace and all pods within will have the same additional configuration applied at scheduling time.

The following options are available for configuration (if existing configuration exists then the new configuration you supply will be appended, it does not replace existing configuration).

  • Environment Variables
  • DNS Options
  • Required Node Affinity terms
  • Preferred Node Affinity terms
  • Tolerations
  • Topology Spread Constraints

Each configuration type is optional so your configmap or values file will only include those that you want to change.

Example config map:

apiVersion: v1
kind: ConfigMap
metadata:
  name: env-injector-webhook-configmap
data:
  envconfig.yaml: |
    tolerations:
      - key: kubernetes.azure.com/scalesetpriority
        effect: NoSchedule
        operator: Equal
        value: spot
    topologyConstraints:
      - maxSkew: 1
        topologyKey: topology.kubernetes.io/zone
        whenUnsatisfiable: ScheduleAnyway
        nodeAffinityPolicy: Honor
        nodeTaintsPolicy: Honor
        labelSelector:
          matchLabels:
            app.kubernetes.io/name: test-app
        matchLabelKeys:
          - pod-template-hash

example values.yaml file (Helm):

environment: {}
dnsOptions: {}
requiredNodeAffinityTerms: {}
preferredNodeAffinityTerms: {}
tolerations:
  - key: kubernetes.azure.com/scalesetpriority
    effect: NoSchedule
    operator: Equal
    value: spot
topologyConstraints:
  - maxSkew: 1
    topologyKey: topology.kubernetes.io/zone
    whenUnsatisfiable: ScheduleAnyway
    nodeAffinityPolicy: Honor
    nodeTaintsPolicy: Honor
    labelSelector:
      matchLabels:
        app.kubernetes.io/name: test-app
    matchLabelKeys:
      - pod-template-hash

Prerequisites

Kubernetes 1.22.0 or above with the admissionregistration.k8s.io/v1 API enabled. Verify that by the following command:

kubectl api-versions | grep admissionregistration.k8s.io/v1

The result should be:

admissionregistration.k8s.io/v1

In addition, the MutatingAdmissionWebhook and ValidatingAdmissionWebhook admission controllers should be added and listed in the correct order in the admission-control flag of kube-apiserver.

Build

Within this repository is a Dockerfile, this should be used when there are changes made to the Golang code.

Build and push docker image

docker build --tag k8s-env-injector:latest .

docker tag k8s-env-injector <your container repository>/k8s-env-injector:<tag>

docker push <your container repository>/k8s-env-injector:<tag>

Deploy

Create a signed cert/key pair and store it in a Kubernetes secret that will be consumed by env-injector deployment

./deployment/webhook-create-signed-cert.sh \
    --service env-injector-webhook-svc \
    --secret env-injector-webhook-certs \
    --namespace default

NOTE: This creates a secret within your namespace so you need to use this namespace for the rest of the deployment steps

Patch the MutatingWebhookConfiguration by set caBundle with correct value from Kubernetes cluster

cat deployment/mutatingwebhook.yaml | \
    deployment/webhook-patch-ca-bundle.sh > \
    deployment/mutatingwebhook-ca-bundle.yaml

This will update the local deployment/mutatingwebhook-ca-bundle.yaml file with a new CA bundle string, make sure to check that it also has the matching namespace file before you deploy.

Deploy resources

kubectl create -f deployment/configmap.yaml
kubectl create -f deployment/deployment.yaml
kubectl create -f deployment/service.yaml
kubectl create -f deployment/mutatingwebhook-ca-bundle.yaml

Verify

The environment inject webhook should be running now in your namespace, you can verify by:

kubectl get pods
NAME                                                  READY     STATUS    RESTARTS   AGE
env-injector-webhook-deployment-bbb689d69-882dd   1/1       Running   0          5m
kubectl get deployment
NAME                                  DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
env-injector-webhook-deployment   1         1         1            1           5m

Add a label to the namespace that you want env-injector to make changes to with: env-injector=enabled

kubectl label namespace default hmcts.github.com/envInjector=enabled
kubectl get namespace -L hmcts.github.com/envInjector

Output:

NAME              STATUS   AGE    ENVINJECTOR
default           Active   4d3h   enabled
kube-node-lease   Active   4d3h   
kube-public       Active   4d3h   
kube-system       Active   4d3h   

Create a test deployment in your namespace, the following is an example that can be used for quick results:

cat <<EOF | kubectl create -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: sleep
spec:
  replicas: 1
  selector:
    matchLabels:
      app: sleep
  template:
    metadata:
      labels:
        app: sleep
    spec:
      containers:
      - name: sleep
        image: hmctspublic.azurecr.io/docker-curl
        command: ["sleep","1d"]
        imagePullPolicy: Always
EOF

To verify that the changes have been applied you can check the output of the pod. The following example is based on using the deployment above:

kubectl get pod -l app=sleep -o json 

You should be able to see your additional config listed as part of the pod spec. If you have JQ installed you can narrow down the results to what you want to see:

kubectl get pod -l app=sleep -o json | jq '.spec.dnsOptions'

Helm chart

A Helm chart is also available, see env-injector-webhook. This can be installed in a single step using helm 2 or 3, e.g.

$ helm upgrade env-injector-webhook env-injector-webhook --install --namespace <your namespace>

Note: As the pods and service need to have:

  • a secret containing a signed certificate and key
  • a mutating webhook patched with the CA Bundle the script executed from pre-install-job.yaml takes care of creating them executing as a helm pre-install + pre-upgrade hook. This allows the installation/upgrade steps to execute in the right order, but has the (unfortunate) side effect of leaving around the secret and mutating webhook when the chart is deleted. For that reason a pre-upgrade + post-delete helm hook takes care of deleting secret and admission webhook.

Updates

If you wish to update or increase the coverage of this webhook you can use the following API Guide for Kubernetes and Golang:

Notes

This repo is based on the excellent tutorial available at: morvencao/kube-mutating-webhook-tutorial

k8s-env-injector's People

Contributors

adusumillipraveen avatar hannah38 avatar luigibk avatar martyfox avatar msl8r avatar renovate[bot] avatar timja avatar tomkukral avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

k8s-env-injector's Issues

Certificate renewal

What would you like to change?

I'd like to avoid using hardcoded certificates and add posibility to restart env-injector on certificate change.

How do you think that would improve the project?

I'd like to update env-injector to automatically restart (just exit 0 and let container to be restarted) when certificate is changes.

I will then use cert-manager to renew certificates for env-injector.

I'm working on this and will send PR.

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

Open

These updates have all been created already. Click a checkbox below to force a retry/rebase of any.

Detected dependencies

dockerfile
image/Dockerfile
  • golang 1.21.6-bullseye
gomod
image/go.mod
  • go 1.21
  • github.com/ghodss/yaml v1.0.0
  • github.com/golang/glog v1.2.1
  • github.com/google/go-cmp v0.6.0
  • k8s.io/api v0.28.4
  • k8s.io/apimachinery v0.28.4
helm-values
env-injector-webhook/values.yaml
  • hmctspublic.azurecr.io/hmcts/k8s-env-injector 496359_20231218

  • Check this box to trigger a request for Renovate to run again on this repository

Environment is not set in example application

Hello and thanks for this tutorial,
Unfortunately I have not been able to reproduce the example scenario (with the sleep application) described in the README.

I have deployed all the components successfully:

$ sudo kubectl get all
NAME                                                  READY   STATUS    RESTARTS   AGE
pod/env-injector-webhook-deployment-db845bd5f-sfxj7   1/1     Running   0          12m
pod/sleep-99dff5b9f-wqq49                             1/1     Running   0          8m33s

NAME                               TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
service/kubernetes                 ClusterIP   10.43.0.1       <none>        443/TCP        52d
service/frontend                   NodePort    10.43.170.163   192.168.1.1   80:30007/TCP   20d
service/env-injector-webhook-svc   ClusterIP   10.43.115.195   <none>        443/TCP        12m

NAME                                              READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/env-injector-webhook-deployment   1/1     1            1           12m
deployment.apps/sleep                             1/1     1            1           8m33s

NAME                                                        DESIRED   CURRENT   READY   AGE
replicaset.apps/env-injector-webhook-deployment-db845bd5f   1         1         1       12m
replicaset.apps/sleep-99dff5b9f                             1         1         1       8m33s

As from the description of the "sleep" example pod, no environment variable has been set:

$ sudo kubectl describe pod sleep-99dff5b9f-wqq49
Name:         sleep-99dff5b9f-wqq49
Namespace:    default
Priority:     0
Node:         bonarda/135.238.224.200
Start Time:   Thu, 08 Apr 2021 18:29:34 +0200
Labels:       app=sleep
              pod-template-hash=99dff5b9f
Annotations:  <none>
Status:       Running
IP:           10.42.0.123
IPs:
  IP:           10.42.0.123
Controlled By:  ReplicaSet/sleep-99dff5b9f
Containers:
  sleep:
    Container ID:  docker://da92dfc65dccc358d1fb62b5691bbc31ee8d348728d9cf9ce7b027d861bd48e0
    Image:         hmctspublic.azurecr.io/docker-curl
    Image ID:      docker-pullable://hmctspublic.azurecr.io/docker-curl@sha256:6eff65c649ae1e8f9a0214e70aa28c1ad1899fe774f6f2e745720b7f1182317c
    Port:          <none>
    Host Port:     <none>
    Command:
      sleep
      1d
    State:          Running
      Started:      Thu, 08 Apr 2021 18:29:37 +0200
    Ready:          True
    Restart Count:  0
    Environment:    <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-vd5hl (ro)
Conditions:
  Type              Status
  Initialized       True
  Ready             True
  ContainersReady   True
  PodScheduled      True
Volumes:
  default-token-vd5hl:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-vd5hl
    Optional:    false
QoS Class:       BestEffort
Node-Selectors:  <none>
Tolerations:     node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
                 node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
  Type    Reason     Age   From               Message
  ----    ------     ----  ----               -------
  Normal  Scheduled  15m   default-scheduler  Successfully assigned default/sleep-99dff5b9f-wqq49 to bonarda
  Normal  Pulling    15m   kubelet            Pulling image "hmctspublic.azurecr.io/docker-curl"
  Normal  Pulled     15m   kubelet            Successfully pulled image "hmctspublic.azurecr.io/docker-curl" in 2.448478445s
  Normal  Created    15m   kubelet            Created container sleep
  Normal  Started    15m   kubelet            Started container sleep

And this is the log from the env-injector pod:

$ sudo kubectl logs pod/env-injector-webhook-deployment-db845bd5f-sfxj7
I0408 16:25:50.663940       1 webhook.go:71] New configuration: sha256sum 7ed3633d452776eb11653f393435373e0040313f667cdc372934726a26855c8a

Add license

Can you please add license file here so we can use this tool on our env?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.