Skip to content

Commit

Permalink
Merge pull request #153 from EDITD/PFM_615_Add_aws_secret_store_settings
Browse files Browse the repository at this point in the history
PFM-615 / Add support to specify to ServiceAccount and SecretProviderClass
  • Loading branch information
DilaraOflaz authored Jun 9, 2023
2 parents d188fd6 + e898c4f commit 8565800
Show file tree
Hide file tree
Showing 14 changed files with 290 additions and 9 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

### Unreleased

# v13.11.0
- Add support to specify SecretProviderClass
- Add support to specify ServiceAccount

# v13.10.0
- Add ability to provide a custom script to check the presence of the image on the target registry
- Re-work checking for CronJob API version compatibility against the target k8s cluster
Expand Down
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@ tests:

deployments:
my-app-webserver:
serviceAccountName: webserver
secrets:
secret-volume:
mountPath: /mnt/secrets-store
secretProviderClass: webserver-secrets
containers:
uwsgi:
command: [uwsgi, --ini, /etc/uwsgi.conf]
Expand Down Expand Up @@ -114,3 +119,6 @@ pip install -e .[dev]
* Copy changes in the release from `CHANGELOG.md` into the release description
* [GitHub Actions](https://github.com/EDITD/kubetools/actions) will package the release and
publish it to [Pypi](https://pypi.org/project/kubetools/)

## Mounting K8s Secrets
We assume that `ServiceAccount` and `SecretProviderClass` are already created (if needed), before deploying the project with kubetools.
15 changes: 15 additions & 0 deletions kubetools/kubernetes/config/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,9 @@ def generate_kubernetes_configs_for_project(
NAME_LABEL_KEY: dependency_name,
})

service_account_name = dependency.get('serviceAccountName', None)
secrets = dependency.get('secrets', None)

containers, container_ports = _get_containers_data(
dependency['containers'],
context_name_to_image=context_name_to_image,
Expand All @@ -196,6 +199,8 @@ def generate_kubernetes_configs_for_project(
annotations=app_annotations,
envvars=envvars,
update_strategy=dependency.get('updateStrategy'),
service_account_name=service_account_name,
secrets=secrets,
))

for name, deployment in config.get('deployments', {}).items():
Expand All @@ -205,6 +210,9 @@ def generate_kubernetes_configs_for_project(
NAME_LABEL_KEY: deployment_name,
})

service_account_name = deployment.get('serviceAccountName', None)
secrets = deployment.get('secrets', None)

containers, container_ports = _get_containers_data(
deployment['containers'],
context_name_to_image=context_name_to_image,
Expand Down Expand Up @@ -234,6 +242,8 @@ def generate_kubernetes_configs_for_project(
annotations=app_annotations,
envvars=envvars,
update_strategy=deployment.get('updateStrategy'),
service_account_name=service_account_name,
secrets=secrets,
))

# Jobs can be upgrades and/or passed in as part of the build spec
Expand Down Expand Up @@ -293,6 +303,9 @@ def generate_kubernetes_configs_for_project(
NAME_LABEL_KEY: name,
})

service_account_name = cronjob.get('serviceAccountName', None)
secrets = cronjob.get('secrets', None)

containers, container_ports = _get_containers_data(
cronjob['containers'],
context_name_to_image=context_name_to_image,
Expand All @@ -315,6 +328,8 @@ def generate_kubernetes_configs_for_project(
labels=cronjob_labels,
annotations=app_annotations,
envvars=envvars,
service_account_name=service_account_name,
secrets=secrets,
))

return services, deployments, jobs, cronjobs
12 changes: 11 additions & 1 deletion kubetools/kubernetes/config/container.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ def _make_probe_config(config):

def make_container_config(
name, container,
envvars=None, labels=None, annotations=None,
envvars=None, labels=None,
annotations=None, secrets=None,
):
'''
Builds the common Kubernetes container config.
Expand Down Expand Up @@ -118,6 +119,15 @@ def make_container_config(
'name': get_hash(volume),
})

if secrets is not None:
container_data['volumeMounts'] = container_data.get('volumeMounts', [])
for secret_name, secret in secrets.items():
container_data['volumeMounts'].append({
'name': secret_name,
'mountPath': secret.get('mountPath'),
'readonly': True,
})

# Finally, attach all remaining data
container_data.update(container)

Expand Down
22 changes: 18 additions & 4 deletions kubetools/kubernetes/config/cronjob.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from .container import make_container_config
from .util import copy_and_update
from .volume import make_secret_volume_config


def make_cronjob_config(
Expand All @@ -14,6 +15,8 @@ def make_cronjob_config(
labels=None,
annotations=None,
envvars=None,
service_account_name=None,
secrets=None,
):
'''
Builds a Kubernetes cronjob configuration dict.
Expand Down Expand Up @@ -43,8 +46,22 @@ def make_cronjob_config(
envvars=envvars,
labels=labels,
annotations=annotations,
secrets=secrets,
))

kubernetes_spec = {}
if service_account_name is not None and secrets is not None:
kubernetes_volumes = []
for secret_name, secret in secrets.items():
kubernetes_volumes.append(make_secret_volume_config(
secret_name, secret,
))
kubernetes_spec['serviceAccountName'] = service_account_name
kubernetes_spec['volumes'] = kubernetes_volumes

kubernetes_spec['restartPolicy'] = 'OnFailure'
kubernetes_spec['containers'] = kubernetes_containers

# The actual cronjob spec
cronjob = {
'kind': 'CronJob',
Expand All @@ -65,10 +82,7 @@ def make_cronjob_config(
'labels': labels,
'annotations': annotations,
},
'spec': {
'restartPolicy': 'OnFailure',
'containers': kubernetes_containers,
},
'spec': kubernetes_spec,
},
},
},
Expand Down
20 changes: 17 additions & 3 deletions kubetools/kubernetes/config/deployment.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from .container import make_container_config
from .util import get_hash, make_dns_safe_name
from .volume import make_secret_volume_config

DEPLOYMENT_REVISION_LIMIT = 5

Expand All @@ -11,6 +12,8 @@ def make_deployment_config(
annotations=None,
envvars=None,
update_strategy=None,
service_account_name=None,
secrets=None,
):
'''
Builds a Kubernetes deployment configuration dict.
Expand All @@ -27,8 +30,21 @@ def make_deployment_config(
envvars=envvars,
labels=labels,
annotations=annotations,
secrets=secrets,
))

kubernetes_spec = {}
if service_account_name is not None and secrets is not None:
kubernetes_volumes = []
for secret_name, secret in secrets.items():
kubernetes_volumes.append(make_secret_volume_config(
secret_name, secret,
))
kubernetes_spec['serviceAccountName'] = service_account_name
kubernetes_spec['volumes'] = kubernetes_volumes

kubernetes_spec['containers'] = kubernetes_containers

# The actual controller Kubernetes config
controller = {
'apiVersion': 'apps/v1',
Expand All @@ -48,9 +64,7 @@ def make_deployment_config(
'metadata': {
'labels': labels,
},
'spec': {
'containers': kubernetes_containers,
},
'spec': kubernetes_spec,
},
},
}
Expand Down
13 changes: 13 additions & 0 deletions kubetools/kubernetes/config/volume.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
def make_secret_volume_config(name, secret):
volume_data = {
'name': name,
'csi': {
'driver': 'secrets-store.csi.k8s.io',
'readOnly': True,
'volumeAttributes': {
'secretProviderClass': secret['secretProviderClass'],
},
},
}

return volume_data
1 change: 1 addition & 0 deletions tests/configs/basic_app/kubetools.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ deployments:
httpGet:
path: /ping


cronjobs:
generic-cronjob:
schedule: "*/1 * * * *"
Expand Down
2 changes: 1 addition & 1 deletion tests/configs/k8s_cronjobs_beta_api_version/kubetools.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,4 @@ cronjobs:
concurrency_policy: "Replace"
containers:
generic-container:
containerContext: generic-context
containerContext: generic-context
50 changes: 50 additions & 0 deletions tests/configs/k8s_with_mounted_secrets/k8s_cronjobs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
kind: CronJob
metadata:
name: generic-cronjob
labels: {
kubetools/name: generic-cronjob,
kubetools/project_name: generic-app-with-secrets,
kubetools/role: cronjob
}
annotations: {
app.kubernetes.io/managed-by: kubetools,
description: 'Run: [''generic-command'']'
}
spec:
schedule: "*/1 * * * *"
startingDeadlineSeconds: 10
concurrencyPolicy: "Allow"
jobTemplate:
spec:
template:
metadata:
name: generic-cronjob
labels: {
kubetools/name: generic-cronjob,
kubetools/project_name: generic-app-with-secrets,
kubetools/role: cronjob
}
annotations: {
app.kubernetes.io/managed-by: kubetools,
description: 'Run: [''generic-command'']'
}
spec:
serviceAccountName: generic-account
containers:
- command: [generic-command]
containerContext: generic-context
env:
- {name: KUBE, value: 'true'}
image: generic-image
imagePullPolicy: 'Always'
name: generic-container
volumeMounts:
- {name: secret-volume, mountPath: /mnt/cronjobs-secrets-store, readonly: True}
restartPolicy: OnFailure
volumes:
- name: secret-volume
csi:
driver: secrets-store.csi.k8s.io
readOnly: true
volumeAttributes:
secretProviderClass: secrets
75 changes: 75 additions & 0 deletions tests/configs/k8s_with_mounted_secrets/k8s_deployments.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
apiVersion: apps/v1
kind: Deployment
metadata:
annotations: {app.kubernetes.io/managed-by: kubetools}
labels: {kubetools/name: generic-app-with-secrets-generic-deployment-with-secrets, kubetools/project_name: generic-app-with-secrets,
kubetools/role: app}
name: generic-app-with-secrets-generic-deployment-with-secrets
spec:
replicas: 1
revisionHistoryLimit: 5
selector:
matchLabels: {kubetools/name: generic-app-with-secrets-generic-deployment-with-secrets, kubetools/project_name: generic-app-with-secrets,
kubetools/role: app}
template:
metadata:
labels: {kubetools/name: generic-app-with-secrets-generic-deployment-with-secrets, kubetools/project_name: generic-app-with-secrets,
kubetools/role: app}
spec:
serviceAccountName: web-api
containers:
- command: [generic-command]
containerContext: generic-context
env:
- {name: KUBE, value: 'true'}
image: generic-image
imagePullPolicy: Always
name: generic-deployment-workers
volumeMounts:
- {name: secret-volume, mountPath: /mnt/secrets-store, readonly: True}
volumes:
- name: secret-volume
csi:
driver: secrets-store.csi.k8s.io
readOnly: true
volumeAttributes:
secretProviderClass: secrets

---

apiVersion: apps/v1
kind: Deployment
metadata:
annotations: {app.kubernetes.io/managed-by: kubetools}
labels: {kubetools/name: generic-app-with-secrets-generic-dependency-with-secrets, kubetools/project_name: generic-app-with-secrets,
kubetools/role: dependency}
name: generic-app-with-secrets-generic-dependency-with-secrets
spec:
replicas: 1
revisionHistoryLimit: 5
selector:
matchLabels: {kubetools/name: generic-app-with-secrets-generic-dependency-with-secrets, kubetools/project_name: generic-app-with-secrets,
kubetools/role: dependency}
template:
metadata:
labels: {kubetools/name: generic-app-with-secrets-generic-dependency-with-secrets, kubetools/project_name: generic-app-with-secrets,
kubetools/role: dependency}
spec:
serviceAccountName: web-api
containers:
- command: [generic-command]
containerContext: generic-context
env:
- {name: KUBE, value: 'true'}
image: generic-image
imagePullPolicy: Always
name: generic-dependency
volumeMounts:
- {name: secret-volume, mountPath: /mnt/secrets-store, readonly: True}
volumes:
- name: secret-volume
csi:
driver: secrets-store.csi.k8s.io
readOnly: true
volumeAttributes:
secretProviderClass: secrets
27 changes: 27 additions & 0 deletions tests/configs/k8s_with_mounted_secrets/k8s_services.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
apiVersion: v1
kind: Service
metadata:
annotations: {app.kubernetes.io/managed-by: kubetools}
labels: {kubetools/name: generic-app-with-secrets-generic-deployment-with-secrets, kubetools/project_name: generic-app-with-secrets, kubetools/role: app}
name: generic-app-with-secrets-generic-deployment-with-secrets
spec:
ports:
- {port: 80, targetPort: 80}
selector: {kubetools/name: generic-app-with-secrets-generic-deployment-with-secrets, kubetools/project_name: generic-app-with-secrets, kubetools/role: app}
type: NodePort

---

apiVersion: v1
kind: Service
metadata:
annotations: {app.kubernetes.io/managed-by: kubetools}
labels: {kubetools/name: generic-app-with-secrets-generic-dependency-with-secrets, kubetools/project_name: generic-app-with-secrets,
kubetools/role: dependency}
name: generic-app-with-secrets-generic-dependency-with-secrets
spec:
ports:
- {port: 80, targetPort: 80}
selector: {kubetools/name: generic-app-with-secrets-generic-dependency-with-secrets, kubetools/project_name: generic-app-with-secrets,
kubetools/role: dependency}
type: NodePort
Loading

0 comments on commit 8565800

Please sign in to comment.