diff --git a/helm-charts/.helmignore b/helm-charts/.helmignore new file mode 100644 index 0000000..0e8a0eb --- /dev/null +++ b/helm-charts/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/helm-charts/Chart.yaml b/helm-charts/Chart.yaml new file mode 100644 index 0000000..e6e5479 --- /dev/null +++ b/helm-charts/Chart.yaml @@ -0,0 +1,42 @@ +apiVersion: v2 +name: aegis +description: Helm chart for aegis + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application +sources: +- https://github.com/shieldworks/aegis + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. +appVersion: "0.18.1" +home: https://aegis.ist/ +icon: https://raw.githubusercontent.com/shieldworks/aegis/main/assets/aegis-banner.png +keywords: + - secrets + +dependencies: + - name: spire + repository: file://charts/spire + version: 0.1.0 + condition: global.deploySpire + - name: safe + repository: file://charts/safe + version: 0.18.1 + - name: sentinel + repository: file://charts/sentinel + version: 0.18.1 diff --git a/helm-charts/README.md b/helm-charts/README.md new file mode 100644 index 0000000..85bb6ae --- /dev/null +++ b/helm-charts/README.md @@ -0,0 +1,46 @@ +# Aegis Helm Chart + +Aegis keeps your secrets secret. With Aegis, you can rest assured that your sensitive data is always secure and protected. Aegis is perfect for securely storing arbitrary configuration information at a central location and securely dispatching it to workloads. + +## Installation + +To use Aegis, follow the steps below: + +1. Add Aegis Helm repository: + + ```bash + helm repo add aegis https://shieldworks.github.io/aegis/ + ``` + +2. Update helm repository: + + ```bash + helm repo update + ``` + +3. Install Aegis using Helm: + + ```bash + helm install aegis aegis/aegis --version 0.1.0 + ``` + +## Options + +The following options can be passed to the `helm install` command to set global variables: + +- `--set global.deploySpire=`: This flag can be passed to install or skip Spire. +- `--set global.baseImage=`: This flag can be passed to install Aegis with the given baseImage Docker image. + +Default values are `true` and `distroless` for `global.deploySpire` and `global.baseImage` respectively. + +Here's an example command with the above options: + +```bash +helm install aegis aegis/helm-charts --version 0.1.0 --set global.deploySpire=true --set global.baseImage=distroless +``` + +Make sure to replace `` and `` with the desired values. + +## License + +This project is licensed under the [MIT License](LICENSE). \ No newline at end of file diff --git a/helm-charts/charts/safe/.helmignore b/helm-charts/charts/safe/.helmignore new file mode 100644 index 0000000..0e8a0eb --- /dev/null +++ b/helm-charts/charts/safe/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/helm-charts/charts/safe/Chart.yaml b/helm-charts/charts/safe/Chart.yaml new file mode 100644 index 0000000..39dc4e2 --- /dev/null +++ b/helm-charts/charts/safe/Chart.yaml @@ -0,0 +1,24 @@ +apiVersion: v2 +name: safe +description: Helm chart for aegis-safe + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. +appVersion: "0.18.1" diff --git a/helm-charts/charts/safe/templates/Deployment.yaml b/helm-charts/charts/safe/templates/Deployment.yaml new file mode 100644 index 0000000..a63978a --- /dev/null +++ b/helm-charts/charts/safe/templates/Deployment.yaml @@ -0,0 +1,100 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "safe.fullname" . }} + namespace: {{ .Values.global.aegis.namespace }} + labels: + {{- include "safe.labels" . | nindent 4 }} +spec: + {{- if not .Values.autoscaling.enabled }} + replicas: {{ .Values.replicaCount }} + {{- end }} + selector: + matchLabels: + {{- include "safe.selectorLabels" . | nindent 6 }} + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "safe.selectorLabels" . | nindent 8 }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "safe.serviceAccountName" . }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + containers: + - name: main + image: "{{ .Values.global.registry }}/{{- include "safe.repository" .}}:{{ .Values.global.images.safe.tag }}" + imagePullPolicy: {{ .Values.global.images.safe.pullPolicy }} + ports: + - containerPort: 8443 + volumeMounts: + - name: spire-agent-socket + mountPath: /spire-agent-socket + readOnly: true + - name: aegis-data + mountPath: /data + - name: aegis-age + mountPath: /key + readOnly: true + # + # You can configure Aegis Safe by providing environment variables. + # + # See https://aegis.ist/docs/configuration for more information about + # these environment variables. + # + # When you don’t explicitly provide env vars here, Aegis Safe will assume + # the default values outlined in the given link above. + # + env: + {{- range .Values.environments }} + - name: {{ .name }} + value: {{ .value | quote }} + {{- end }} + - name: AEGIS_SENTINEL_SVID_PREFIX + value: "spiffe://aegis.ist/workload/aegis-sentinel/ns/{{ .Values.global.aegis.namespace }}/sa/aegis-sentinel/n/" + - name: AEGIS_SAFE_SVID_PREFIX + value: "spiffe://aegis.ist/workload/aegis-safe/ns/{{ .Values.global.aegis.namespace }}/sa/aegis-safe/n/" + - name: AEGIS_PROBE_LIVENESS_PORT + value: ":{{ .Values.livenessPort }}" + - name: AEGIS_PROBE_READINESS_PORT + value: ":{{ .Values.readynessPort }}" + livenessProbe: + httpGet: + path: / + port: {{ .Values.livenessPort }} + initialDelaySeconds: 1 + periodSeconds: 10 + readinessProbe: + httpGet: + path: / + port: {{ .Values.readynessPort }} + initialDelaySeconds: 1 + periodSeconds: 10 + resources: + {{- toYaml .Values.resources | nindent 12 }} + volumes: + # Using SPIFFE CSI Driver to bind to the SPIRE Agent Socket + # ref: https://github.com/spiffe/spiffe-csi + - name: spire-agent-socket + csi: + driver: "csi.spiffe.io" + readOnly: true + # `aegis-data` is used to persist the encrypted backups of the secrets. + - name: aegis-data + hostPath: + path: /var/local/aegis/data + type: DirectoryOrCreate + # `aegis-age` stores the encryption keys to restore secrets from aegis-data. + - name: aegis-age + secret: + secretName: {{ .Values.ageKeySecretName }} + items: + - key: KEY_TXT + path: key.txt diff --git a/helm-charts/charts/safe/templates/_helpers.tpl b/helm-charts/charts/safe/templates/_helpers.tpl new file mode 100644 index 0000000..70dca90 --- /dev/null +++ b/helm-charts/charts/safe/templates/_helpers.tpl @@ -0,0 +1,80 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "safe.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "safe.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "safe.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "safe.labels" -}} +helm.sh/chart: {{ include "safe.chart" . }} +{{ include "safe.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "safe.selectorLabels" -}} +app.kubernetes.io/name: {{ include "safe.fullname" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +app.kubernetes.io/part-of: {{ .Values.global.aegis.namespace }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "safe.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "safe.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} + +{{/* +Define image for aegis safe +*/}} +{{- define "safe.repository" -}} +{{- if eq (lower $.Values.global.baseImage) "distroless" }} +{{- .Values.global.images.safe.distrolessRepository }} +{{- else if eq (lower $.Values.global.baseImage) "distroless-fips" }} +{{- .Values.global.images.safe.distrolessFipsRepository }} +{{- else if eq (lower $.Values.global.baseImage) "photon" }} +{{- .Values.global.images.safe.photonRepository }} +{{- else if eq (lower $.Values.global.baseImage) "photon-fips" }} +{{- .Values.global.images.safe.photonFipsRepository }} +{{- else }} +{{- .Values.global.images.safe.distrolessRepository }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/helm-charts/charts/safe/templates/hook-preinstall_role.yaml b/helm-charts/charts/safe/templates/hook-preinstall_role.yaml new file mode 100644 index 0000000..dec276f --- /dev/null +++ b/helm-charts/charts/safe/templates/hook-preinstall_role.yaml @@ -0,0 +1,68 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: secret-readwriter +# +# Creating a `ClusterRole` will make the role applicable to all namespaces +# within the cluster. This approach is easier to maintain, and still secure +# enough because Aegis Safe will talk only to the Secrets it knows about. +# Alternatively, you can create a `Role` for tighter control: +# +# kind: Role +# metadata: +# name: secret-readwriter +# namespace: {{ .Values.global.aegis.namespace }} +# +## + +## +# +# It is not possible to implement a more granular regex-based +# access control using RBAC. See, for example: +# https://github.com/kubernetes/kubernetes/issues/93845 +# +# Also, note that you will either need to specify one role for each +# namespace, or you will need to define a ClusterRole across the cluster. +# The former approach is tedious, yet more explicit, and more secure. +# +# If you are NOT planning to use Kubernetes Secrets to sync Aegis-Safe-generated +# secrets (i.e., if AEGIS_SAFE_USE_KUBERNETES_SECRETS is "false"), then +# you can limit the scope of this role as follows: +# +# rules +# - apiGroups: [""] +# resources: ["secrets"] +# resourceNames: [{{ .Values.ageKeySecretName | quote }}] +# verbs: ["get", "watch", "list", "update"] +# +# When the above rule is defined and when AEGIS_SAFE_USE_KUBERNETES_SECRETS +# environment variable is either not set, or set to anything other than "true", +# then you can only consume Aegis-managed secrets through Aegis Safe API, either +# by using the Aegis SDK, or leveraging Aegis Sidecar—which is the recommended +# way. +# +## + +## +# +# This `rules` setting is for legacy support (see the above discussion): +rules: + - apiGroups: [""] + resources: ["secrets"] + verbs: ["get", "watch", "list", "update"] +# +# This `rules` configuration is the recommended, more secure, way: +# +# rules: +# - apiGroups: [""] +# resources: ["secrets"] +# resourceNames: [{{ .Values.ageKeySecretName | quote }}] +# verbs: ["get", "watch", "list", "update"] +# +# +## + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 4 }} + "helm.sh/hook-weight": "2" + {{- end }} diff --git a/helm-charts/charts/safe/templates/identity.yaml b/helm-charts/charts/safe/templates/identity.yaml new file mode 100644 index 0000000..95b6fde --- /dev/null +++ b/helm-charts/charts/safe/templates/identity.yaml @@ -0,0 +1,17 @@ +apiVersion: spire.spiffe.io/v1alpha1 +kind: ClusterSPIFFEID +metadata: + name: {{ include "safe.fullname" . }} +spec: + spiffeIDTemplate: "spiffe://aegis.ist\ + /workload/{{ include "safe.fullname" . }}\ + /ns/{{`{{ .PodMeta.Namespace }}`}}\ + /sa/{{`{{ .PodSpec.ServiceAccountName }}`}}\ + /n/{{`{{ .PodMeta.Name }}`}}" + podSelector: + matchLabels: + app.kubernetes.io/name: {{ include "safe.fullname" . }} + app.kubernetes.io/part-of: {{ .Values.global.aegis.namespace }} + workloadSelectorTemplates: + - "k8s:ns:{{`{{ .PodMeta.Namespace }}`}}" + - "k8s:sa:{{`{{ .PodSpec.ServiceAccountName }}`}}" diff --git a/helm-charts/charts/safe/templates/role_binding.yaml b/helm-charts/charts/safe/templates/role_binding.yaml new file mode 100644 index 0000000..4529d3b --- /dev/null +++ b/helm-charts/charts/safe/templates/role_binding.yaml @@ -0,0 +1,34 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: secret-readwriter-binding +subjects: + - kind: ServiceAccount + name: aegis-safe + namespace: {{ .Values.global.aegis.namespace }} +roleRef: + kind: ClusterRole + name: secret-readwriter + apiGroup: rbac.authorization.k8s.io + +## +# +# Alternatively, for a tighter security, you can define a `RoleBinding` +# instead of a `ClusterRoleBinding`. It will be more secure, yet harder to +# maintain. See the discussion about above `Role`s and `RoleBinding`s. +# +# apiVersion: rbac.authorization.k8s.io/v1 +# kind: RoleBinding +# metadata: +# name: secret-readwriter-binding +# namespace: {{ .Values.global.aegis.namespace }} +# subjects: +# - kind: ServiceAccount +# name: aegis-safe +# namespace: {{ .Values.global.aegis.namespace }} +# roleRef: +# kind: Role +# name: secret-readwriter +# apiGroup: rbac.authorization.k8s.io +# +## diff --git a/helm-charts/charts/safe/templates/secret.yaml b/helm-charts/charts/safe/templates/secret.yaml new file mode 100644 index 0000000..c53432d --- /dev/null +++ b/helm-charts/charts/safe/templates/secret.yaml @@ -0,0 +1,10 @@ +apiVersion: v1 +kind: Secret +metadata: + name: {{ .Values.ageKeySecretName }} + namespace: {{ .Values.global.aegis.namespace }} +type: Opaque +data: + # '{}' (e30=) is a special placeholder to tell Safe that the Secret + # is not initialized. DO NOT remove or change it. + KEY_TXT: "e30=" diff --git a/helm-charts/charts/safe/templates/service.yaml b/helm-charts/charts/safe/templates/service.yaml new file mode 100644 index 0000000..81c5839 --- /dev/null +++ b/helm-charts/charts/safe/templates/service.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "safe.fullname" . }} + namespace: {{ .Values.global.aegis.namespace }} + labels: + {{- include "safe.labels" . | nindent 4 }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: {{ .Values.service.targetPort }} + protocol: TCP + name: http + selector: + {{- include "safe.selectorLabels" . | nindent 4 }} diff --git a/helm-charts/charts/safe/templates/serviceaccount.yaml b/helm-charts/charts/safe/templates/serviceaccount.yaml new file mode 100644 index 0000000..c81e1ff --- /dev/null +++ b/helm-charts/charts/safe/templates/serviceaccount.yaml @@ -0,0 +1,14 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "safe.serviceAccountName" . }} + namespace: {{ .Values.global.aegis.namespace }} + labels: + {{- include "safe.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +automountServiceAccountToken: true +{{- end }} diff --git a/helm-charts/charts/safe/templates/tests/test-connection.yaml b/helm-charts/charts/safe/templates/tests/test-connection.yaml new file mode 100644 index 0000000..3686a75 --- /dev/null +++ b/helm-charts/charts/safe/templates/tests/test-connection.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Pod +metadata: + name: "{{ include "safe.fullname" . }}-test-connection" + labels: + {{- include "safe.labels" . | nindent 4 }} + annotations: + "helm.sh/hook": test +spec: + containers: + - name: wget + image: busybox + command: ['wget'] + args: ['{{ include "safe.fullname" . }}:{{ .Values.service.port }}'] + restartPolicy: Never diff --git a/helm-charts/charts/safe/values.yaml b/helm-charts/charts/safe/values.yaml new file mode 100644 index 0000000..e770ca3 --- /dev/null +++ b/helm-charts/charts/safe/values.yaml @@ -0,0 +1,93 @@ +# Default values for safe. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +replicaCount: 1 + +livenessPort: 8081 +readynessPort: 8082 +ageKeySecretName: &ageKeySecretName aegis-safe-age-key + +environments: + - name: SPIFFE_ENDPOINT_SOCKET + value: "unix:///spire-agent-socket/agent.sock" + - name: AEGIS_LOG_LEVEL + value: "7" + - name: AEGIS_WORKLOAD_SVID_PREFIX + value: "spiffe://aegis.ist/workload/" + - name: AEGIS_SAFE_DATA_PATH + value: "/data" + - name: AEGIS_CRYPTO_KEY_NAME + value: *ageKeySecretName + - name: AEGIS_CRYPTO_KEY_PATH + value: "/key/key.txt" + - name: AEGIS_SAFE_MANUAL_KEY_INPUT + value: "false" + - name: AEGIS_SAFE_SECRET_NAME_PREFIX + value: "aegis-secret-" + - name: AEGIS_SAFE_TLS_PORT + value: ":8443" + - name: AEGIS_SAFE_SECRET_BUFFER_SIZE + value: "10" + - name: AEGIS_SAFE_K8S_SECRET_BUFFER_SIZE + value: "10" + - name: AEGIS_SAFE_SECRET_DELETE_BUFFER_SIZE + value: "10" + - name: AEGIS_SAFE_K8S_SECRET_DELETE_BUFFER_SIZE + value: "10" + - name: AEGIS_SAFE_USE_KUBERNETES_SECRETS + value: "false" + - name: AEGIS_SAFE_BOOTSTRAP_TIMEOUT + value: "30000" + - name: AEGIS_SAFE_FIPS_COMPLIANT + value: "false" + +imagePullSecrets: [] +nameOverride: "" +fullnameOverride: "" + +serviceAccount: + # Specifies whether a service account should be created + create: true + # Annotations to add to the service account + annotations: {} + # The name of the service account to use. + # If not set and create is true, a name is generated using the fullname template + name: "" + +podAnnotations: {} + +podSecurityContext: {} + # fsGroup: 2000 + +securityContext: {} + # capabilities: + # drop: + # - ALL + # readOnlyRootFilesystem: true + # runAsNonRoot: true + # runAsUser: 1000 + +service: + type: ClusterIP + port: 8443 + targetPort: 8443 + +resources: {} + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + +autoscaling: + enabled: false + minReplicas: 1 + maxReplicas: 100 + targetCPUUtilizationPercentage: 80 + # targetMemoryUtilizationPercentage: 80 diff --git a/helm-charts/charts/sentinel/.helmignore b/helm-charts/charts/sentinel/.helmignore new file mode 100644 index 0000000..0e8a0eb --- /dev/null +++ b/helm-charts/charts/sentinel/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/helm-charts/charts/sentinel/Chart.yaml b/helm-charts/charts/sentinel/Chart.yaml new file mode 100644 index 0000000..d0db87e --- /dev/null +++ b/helm-charts/charts/sentinel/Chart.yaml @@ -0,0 +1,24 @@ +apiVersion: v2 +name: sentinel +description: Helm chart for sentinel + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. +appVersion: "0.18.1" diff --git a/helm-charts/charts/sentinel/templates/Deployment.yaml b/helm-charts/charts/sentinel/templates/Deployment.yaml new file mode 100644 index 0000000..b9a4e2e --- /dev/null +++ b/helm-charts/charts/sentinel/templates/Deployment.yaml @@ -0,0 +1,73 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "sentinel.fullname" . }} + namespace: {{ .Values.global.aegis.namespace }} + labels: + {{- include "sentinel.labels" . | nindent 4 }} +spec: + {{- if not .Values.autoscaling.enabled }} + replicas: {{ .Values.replicaCount }} + {{- end }} + selector: + matchLabels: + {{- include "sentinel.selectorLabels" . | nindent 6 }} + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "sentinel.selectorLabels" . | nindent 8 }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "sentinel.serviceAccountName" . }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + containers: + - name: main + image: "{{ .Values.global.registry }}/{{- include "sentinel.repository" .}}:{{ .Values.global.images.sentinel.tag }}" + imagePullPolicy: {{ .Values.global.images.sentinel.pullPolicy }} + volumeMounts: + - name: spire-agent-socket + mountPath: /spire-agent-socket + readOnly: true + # + # You can configure Aegis Sentinel by providing environment variables. + # + # See https://aegis.ist/docs/configuration for more information about + # these environment variables. + # + # When you don’t explicitly provide env vars here, Aegis Sentinel will + # assume the default values outlined in the given link above. + # + env: + {{- range .Values.environments }} + - name: {{ .name }} + value: {{ .value }} + {{- end }} + - name: AEGIS_SENTINEL_SVID_PREFIX + value: "spiffe://aegis.ist/workload/aegis-sentinel/ns/{{ .Values.global.aegis.namespace }}/sa/aegis-sentinel/n/" + - name: AEGIS_SAFE_SVID_PREFIX + value: "spiffe://aegis.ist/workload/aegis-safe/ns/{{ .Values.global.aegis.namespace }}/sa/aegis-safe/n/" + - name: AEGIS_PROBE_LIVENESS_PORT + value: ":{{ .Values.livenessPort }}" + livenessProbe: + httpGet: + path: / + port: {{ .Values.livenessPort }} + initialDelaySeconds: 1 + periodSeconds: 10 + resources: + {{- toYaml .Values.resources | nindent 12 }} + volumes: + # Using SPIFFE CSI Driver to bind to the SPIRE Agent Socket + # ref: https://github.com/spiffe/spiffe-csi + - name: spire-agent-socket + csi: + driver: "csi.spiffe.io" + readOnly: true diff --git a/helm-charts/charts/sentinel/templates/_helpers.tpl b/helm-charts/charts/sentinel/templates/_helpers.tpl new file mode 100644 index 0000000..29ca50d --- /dev/null +++ b/helm-charts/charts/sentinel/templates/_helpers.tpl @@ -0,0 +1,80 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "sentinel.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "sentinel.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "sentinel.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "sentinel.labels" -}} +helm.sh/chart: {{ include "sentinel.chart" . }} +{{ include "sentinel.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "sentinel.selectorLabels" -}} +app.kubernetes.io/name: {{ include "sentinel.fullname" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +app.kubernetes.io/part-of: {{ .Values.global.aegis.namespace }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "sentinel.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "sentinel.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} + +{{/* +Define image for aegis sentinel +*/}} +{{- define "sentinel.repository" -}} +{{- if eq (lower $.Values.global.baseImage) "distroless" }} +{{- .Values.global.images.sentinel.distrolessRepository }} +{{- else if eq (lower $.Values.global.baseImage) "distroless-fips" }} +{{- .Values.global.images.sentinel.distrolessFipsRepository }} +{{- else if eq (lower $.Values.global.baseImage) "photon" }} +{{- .Values.global.images.sentinel.photonRepository }} +{{- else if eq (lower $.Values.global.baseImage) "photon-fips" }} +{{- .Values.global.images.sentinel.photonFipsRepository }} +{{- else }} +{{- .Values.global.images.sentinel.distrolessRepository }} +{{- end }} +{{- end }} diff --git a/helm-charts/charts/sentinel/templates/identity.yaml b/helm-charts/charts/sentinel/templates/identity.yaml new file mode 100644 index 0000000..8331228 --- /dev/null +++ b/helm-charts/charts/sentinel/templates/identity.yaml @@ -0,0 +1,17 @@ +apiVersion: spire.spiffe.io/v1alpha1 +kind: ClusterSPIFFEID +metadata: + name: {{ include "sentinel.fullname" . }} +spec: + spiffeIDTemplate: "spiffe://aegis.ist\ + /workload/{{ include "sentinel.fullname" . }}\ + /ns/{{`{{ .PodMeta.Namespace }}`}}\ + /sa/{{`{{ .PodSpec.ServiceAccountName }}`}}\ + /n/{{`{{ .PodMeta.Name }}`}}" + podSelector: + matchLabels: + app.kubernetes.io/name: {{ include "sentinel.fullname" . }} + app.kubernetes.io/part-of: {{ .Values.global.aegis.namespace }} + workloadSelectorTemplates: + - "k8s:ns:{{`{{ .PodMeta.Namespace }}`}}" + - "k8s:sa:{{`{{ .PodSpec.ServiceAccountName }}`}}" diff --git a/helm-charts/charts/sentinel/templates/serviceaccount.yaml b/helm-charts/charts/sentinel/templates/serviceaccount.yaml new file mode 100644 index 0000000..9de4c4d --- /dev/null +++ b/helm-charts/charts/sentinel/templates/serviceaccount.yaml @@ -0,0 +1,14 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "sentinel.serviceAccountName" . }} + namespace: {{ .Values.global.aegis.namespace }} + labels: + {{- include "sentinel.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +automountServiceAccountToken: false +{{- end }} diff --git a/helm-charts/charts/sentinel/values.yaml b/helm-charts/charts/sentinel/values.yaml new file mode 100644 index 0000000..247e1f6 --- /dev/null +++ b/helm-charts/charts/sentinel/values.yaml @@ -0,0 +1,56 @@ +# Default values for sentinel. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +replicaCount: 1 + +livenessPort: 8081 + +environments: + - name: SPIFFE_ENDPOINT_SOCKET + value: "unix:///spire-agent-socket/agent.sock" + +imagePullSecrets: [] +nameOverride: "" +fullnameOverride: "" + +serviceAccount: + # Specifies whether a service account should be created + create: true + # Annotations to add to the service account + annotations: {} + # The name of the service account to use. + # If not set and create is true, a name is generated using the fullname template + name: "" + +podAnnotations: {} + +podSecurityContext: {} + # fsGroup: 2000 + +securityContext: {} + # capabilities: + # drop: + # - ALL + # readOnlyRootFilesystem: true + # runAsNonRoot: true + # runAsUser: 1000 + +resources: {} + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + +autoscaling: + enabled: false + minReplicas: 1 + maxReplicas: 100 + targetCPUUtilizationPercentage: 80 + # targetMemoryUtilizationPercentage: 80 diff --git a/helm-charts/charts/spire/.helmignore b/helm-charts/charts/spire/.helmignore new file mode 100644 index 0000000..0e8a0eb --- /dev/null +++ b/helm-charts/charts/spire/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/helm-charts/charts/spire/Chart.yaml b/helm-charts/charts/spire/Chart.yaml new file mode 100644 index 0000000..8c2328b --- /dev/null +++ b/helm-charts/charts/spire/Chart.yaml @@ -0,0 +1,24 @@ +apiVersion: v2 +name: spire +description: Helm chart for spire + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. +appVersion: "1.16.0" diff --git a/helm-charts/charts/spire/templates/_helpers.tpl b/helm-charts/charts/spire/templates/_helpers.tpl new file mode 100644 index 0000000..42def7c --- /dev/null +++ b/helm-charts/charts/spire/templates/_helpers.tpl @@ -0,0 +1,62 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "spire.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "spire.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "spire.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "spire.labels" -}} +helm.sh/chart: {{ include "spire.chart" . }} +{{ include "spire.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "spire.selectorLabels" -}} +app.kubernetes.io/name: {{ include "spire.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "spire.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "spire.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/helm-charts/charts/spire/templates/crd-rbac/hook-preinstall_leader_election_role.yaml b/helm-charts/charts/spire/templates/crd-rbac/hook-preinstall_leader_election_role.yaml new file mode 100644 index 0000000..31480e0 --- /dev/null +++ b/helm-charts/charts/spire/templates/crd-rbac/hook-preinstall_leader_election_role.yaml @@ -0,0 +1,16 @@ +# permissions to do leader election. +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: leader-election-role + namespace: {{ .Values.global.spire.namespace }} +rules: + - apiGroups: [""] + resources: ["configmaps"] + verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] + - apiGroups: ["coordination.k8s.io"] + resources: ["leases"] + verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] + - apiGroups: [""] + resources: ["events"] + verbs: ["create", "patch"] diff --git a/helm-charts/charts/spire/templates/crd-rbac/hook-preinstall_role.yaml b/helm-charts/charts/spire/templates/crd-rbac/hook-preinstall_role.yaml new file mode 100644 index 0000000..7b0a379 --- /dev/null +++ b/helm-charts/charts/spire/templates/crd-rbac/hook-preinstall_role.yaml @@ -0,0 +1,44 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: manager-role +rules: + - apiGroups: [""] + resources: ["namespaces"] + verbs: ["get", "list", "watch"] + - apiGroups: ["admissionregistration.k8s.io"] + resources: ["validatingwebhookconfigurations"] + verbs: ["get", "list", "patch", "watch"] + - apiGroups: [""] + resources: ["nodes"] + verbs: ["get", "list", "watch"] + - apiGroups: [""] + resources: ["pods"] + verbs: ["get", "list", "watch"] + - apiGroups: ["spire.spiffe.io"] + resources: ["clusterfederatedtrustdomains"] + verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] + - apiGroups: ["spire.spiffe.io"] + resources: ["clusterfederatedtrustdomains/finalizers"] + verbs: ["update"] + - apiGroups: ["spire.spiffe.io"] + resources: ["clusterfederatedtrustdomains/status"] + verbs: ["get", "patch", "update"] + - apiGroups: ["spire.spiffe.io"] + resources: ["clusterspiffeids"] + verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] + - apiGroups: ["spire.spiffe.io"] + resources: ["clusterspiffeids/finalizers"] + verbs: ["update"] + - apiGroups: ["spire.spiffe.io"] + resources: ["clusterspiffeids/status"] + verbs: ["get", "patch", "update"] + - apiGroups: ["spire.spiffe.io"] + resources: ["clusterstaticentries"] + verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] + - apiGroups: ["spire.spiffe.io"] + resources: ["clusterstaticentries/finalizers"] + verbs: ["update"] + - apiGroups: ["spire.spiffe.io"] + resources: ["clusterstaticentries/status"] + verbs: ["get", "patch", "update"] diff --git a/helm-charts/charts/spire/templates/crd-rbac/leader_election_role_binding.yaml b/helm-charts/charts/spire/templates/crd-rbac/leader_election_role_binding.yaml new file mode 100644 index 0000000..b47adf5 --- /dev/null +++ b/helm-charts/charts/spire/templates/crd-rbac/leader_election_role_binding.yaml @@ -0,0 +1,13 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: leader-election-rolebinding + namespace: {{ .Values.global.spire.namespace }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: leader-election-role +subjects: + - kind: ServiceAccount + name: spire-server + namespace: {{ .Values.global.spire.namespace }} diff --git a/helm-charts/charts/spire/templates/crd-rbac/role_binding.yaml b/helm-charts/charts/spire/templates/crd-rbac/role_binding.yaml new file mode 100644 index 0000000..552b3f8 --- /dev/null +++ b/helm-charts/charts/spire/templates/crd-rbac/role_binding.yaml @@ -0,0 +1,12 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: manager-rolebinding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: manager-role +subjects: + - kind: ServiceAccount + name: spire-server + namespace: {{ .Values.global.spire.namespace }} diff --git a/helm-charts/charts/spire/templates/hook-preinstall_spiffe-csi-driver.yaml b/helm-charts/charts/spire/templates/hook-preinstall_spiffe-csi-driver.yaml new file mode 100644 index 0000000..3de2889 --- /dev/null +++ b/helm-charts/charts/spire/templates/hook-preinstall_spiffe-csi-driver.yaml @@ -0,0 +1,22 @@ +apiVersion: storage.k8s.io/v1 +kind: CSIDriver +metadata: + name: "csi.spiffe.io" +spec: + # We only support ephemeral, inline volumes. We don't need a controller to + # provision and attach volumes. + attachRequired: false + + # We want the pod information so that the CSI driver can verify that an + # ephemeral mount was requested. + podInfoOnMount: true + + # We don't want (or need) K8s to change ownership on the contents of the mount + # when it is moutned into the pod, since the Workload API is completely open + # (i.e. 0777). + # Note, this was added in Kubernetes 1.19, so omit + fsGroupPolicy: None + + # We only support ephemeral volumes. Note that this requires Kubernetes 1.16 + volumeLifecycleModes: # added in Kubernetes 1.16, this field is beta + - Ephemeral diff --git a/helm-charts/charts/spire/templates/hook-preinstall_spire-namespace.yaml b/helm-charts/charts/spire/templates/hook-preinstall_spire-namespace.yaml new file mode 100644 index 0000000..5c56730 --- /dev/null +++ b/helm-charts/charts/spire/templates/hook-preinstall_spire-namespace.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: {{ .Values.global.spire.namespace }} diff --git a/helm-charts/charts/spire/templates/spire-agent.yaml b/helm-charts/charts/spire/templates/spire-agent.yaml new file mode 100644 index 0000000..a07ac0c --- /dev/null +++ b/helm-charts/charts/spire/templates/spire-agent.yaml @@ -0,0 +1,210 @@ +# ServiceAccount for the SPIRE agent +apiVersion: v1 +kind: ServiceAccount +metadata: + name: spire-agent + namespace: {{ .Values.global.spire.namespace }} + +--- + +# Required cluster role to allow spire-agent to query k8s API server +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: spire-agent-cluster-role +rules: + - apiGroups: [""] + resources: ["pods","nodes","nodes/proxy"] + verbs: ["get"] + +--- + +# Binds above cluster role to spire-agent service account +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: spire-agent-cluster-role-binding +subjects: + - kind: ServiceAccount + name: spire-agent + namespace: {{ .Values.global.spire.namespace }} +roleRef: + kind: ClusterRole + name: spire-agent-cluster-role + apiGroup: rbac.authorization.k8s.io + + +--- + +# ConfigMap for the SPIRE agent featuring: +# 1) PSAT node attestation +# 2) K8S Workload Attestation over the secure kubelet port +apiVersion: v1 +kind: ConfigMap +metadata: + name: spire-agent + namespace: {{ .Values.global.spire.namespace }} +data: + agent.conf: | + agent { + data_dir = "/run/spire" + log_level = {{ .Values.global.spire.logLevel | quote }} + server_address = "spire-server" + server_port = {{ .Values.global.spire.serverPort | quote }} + socket_path = "/run/spire/sockets/agent.sock" + trust_bundle_path = "/run/spire/bundle/bundle.crt" + trust_domain = "aegis.ist" + } + + plugins { + NodeAttestor "k8s_psat" { + plugin_data { + cluster = "aegis-cluster" + } + } + + KeyManager "memory" { + plugin_data { + } + } + + WorkloadAttestor "k8s" { + plugin_data { + skip_kubelet_verification = true + } + } + } + +--- + +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: spire-agent + namespace: {{ .Values.global.spire.namespace }} + labels: + app: spire-agent +spec: + selector: + matchLabels: + app: spire-agent + updateStrategy: + type: RollingUpdate + template: + metadata: + namespace: {{ .Values.global.spire.namespace }} + labels: + app: spire-agent + spec: + hostPID: true + hostNetwork: true + dnsPolicy: ClusterFirstWithHostNet + serviceAccountName: spire-agent + containers: + - name: spire-agent + image: {{ .Values.global.images.spireAgent.repository }}:{{ .Values.global.images.spireAgent.tag }} + imagePullPolicy: {{ .Values.global.images.spireAgent.pullPolicy }} + args: ["-config", "/run/spire/config/agent.conf"] + volumeMounts: + - name: spire-config + mountPath: /run/spire/config + readOnly: true + - name: spire-bundle + mountPath: /run/spire/bundle + readOnly: true + - name: spire-token + mountPath: /var/run/secrets/tokens + - name: spire-agent-socket-dir + mountPath: /run/spire/sockets + # This is the container which runs the SPIFFE CSI driver. + - name: spiffe-csi-driver + image: {{ .Values.global.images.spiffeCsiDriver.repository }}:{{ .Values.global.images.spiffeCsiDriver.tag }} + imagePullPolicy: {{ .Values.global.images.spiffeCsiDriver.pullPolicy }} + args: [ + "-workload-api-socket-dir", "/spire-agent-socket", + "-csi-socket-path", "/spiffe-csi/csi.sock", + ] + env: + # The CSI driver needs a unique node ID. The node name can be + # used for this purpose. + - name: MY_NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + volumeMounts: + # The volume containing the SPIRE agent socket. The SPIFFE CSI + # driver will mount this directory into containers. + - mountPath: /spire-agent-socket + name: spire-agent-socket-dir + readOnly: true + # The volume that will contain the CSI driver socket shared + # with the kubelet and the driver registrar. + - mountPath: /spiffe-csi + name: spiffe-csi-socket-dir + # The volume containing mount points for containers. + - mountPath: /var/lib/kubelet/pods + mountPropagation: Bidirectional + name: mountpoint-dir + securityContext: + privileged: true + # This container runs the CSI Node Driver Registrar which takes care + # of all the little details required to register a CSI driver with + # the kubelet. + - name: node-driver-registrar + image: {{ .Values.global.images.nodeDriverRegistrar.repository }}:{{ .Values.global.images.nodeDriverRegistrar.tag }} + imagePullPolicy: {{ .Values.global.images.nodeDriverRegistrar.pullPolicy }} + args: [ + "-csi-address", "/spiffe-csi/csi.sock", + "-kubelet-registration-path", "/var/lib/kubelet/plugins/csi.spiffe.io/csi.sock", + ] + volumeMounts: + # The registrar needs access to the SPIFFE CSI driver socket + - mountPath: /spiffe-csi + name: spiffe-csi-socket-dir + # The registrar needs access to the Kubelet plugin registration + # directory + - name: kubelet-plugin-registration-dir + mountPath: /registration + volumes: + - name: spire-config + configMap: + name: spire-agent + - name: spire-bundle + configMap: + name: spire-bundle + - name: spire-token + projected: + sources: + - serviceAccountToken: + path: spire-agent + expirationSeconds: 7200 + audience: spire-server + + # This volume is used to share the Workload API socket between the CSI + # driver and SPIRE agent. Note, an emptyDir volume could also be used, + # however, this can lead to broken bind mounts in the workload + # containers if the agent pod is restarted (since the emptyDir + # directory on the node that was mounted into workload containers by + # the CSI driver belongs to the old pod instance and is no longer + # valid). + - name: spire-agent-socket-dir + hostPath: + path: /run/spire/sockets + type: DirectoryOrCreate + + # This volume is where the socket for kubelet->driver communication lives + - name: spiffe-csi-socket-dir + hostPath: + path: /var/lib/kubelet/plugins/csi.spiffe.io + type: DirectoryOrCreate + # This volume is where the SPIFFE CSI driver mounts volumes + - name: mountpoint-dir + hostPath: + path: /var/lib/kubelet/pods + type: Directory + # This volume is where the node-driver-registrar registers the plugin + # with kubelet + - name: kubelet-plugin-registration-dir + hostPath: + path: /var/lib/kubelet/plugins_registry + type: Directory diff --git a/helm-charts/charts/spire/templates/spire-controller-manager-config.yaml b/helm-charts/charts/spire/templates/spire-controller-manager-config.yaml new file mode 100644 index 0000000..a63c8b2 --- /dev/null +++ b/helm-charts/charts/spire/templates/spire-controller-manager-config.yaml @@ -0,0 +1,29 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: spire-controller-manager-config + namespace: {{ .Values.global.spire.namespace }} +data: + spire-controller-manager-config.yaml: | + apiVersion: spire.spiffe.io/v1alpha1 + kind: ControllerManagerConfig + metrics: + bindAddress: 127.0.0.1:8082 + healthProbe: + bindAddress: 127.0.0.1:8083 + leaderElection: + leaderElect: true + resourceName: 98c9c988.spiffe.io + resourceNamespace: {{ .Values.global.spire.namespace }} + clusterName: aegis-cluster + trustDomain: aegis.ist + ignoreNamespaces: + - kube-system + - kube-public + - {{ .Values.global.spire.namespace }} + - local-path-storage + # - do not ignore aegis-system! + # - aegis-system + - kube-node-lease + - kube-public + - kubernetes-dashboard diff --git a/helm-charts/charts/spire/templates/spire-controller-manager-webhook.yaml b/helm-charts/charts/spire/templates/spire-controller-manager-webhook.yaml new file mode 100644 index 0000000..f41d51c --- /dev/null +++ b/helm-charts/charts/spire/templates/spire-controller-manager-webhook.yaml @@ -0,0 +1,47 @@ +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingWebhookConfiguration +metadata: + name: spire-controller-manager-webhook +webhooks: + - admissionReviewVersions: ["v1"] + clientConfig: + service: + name: spire-controller-manager-webhook-service + namespace: {{ .Values.global.spire.namespace }} + path: /validate-spire-spiffe-io-v1alpha1-clusterfederatedtrustdomain + failurePolicy: Fail + name: vclusterfederatedtrustdomain.kb.io + rules: + - apiGroups: ["spire.spiffe.io"] + apiVersions: ["v1alpha1"] + operations: ["CREATE", "UPDATE"] + resources: ["clusterfederatedtrustdomains"] + sideEffects: None + - admissionReviewVersions: ["v1"] + clientConfig: + service: + name: spire-controller-manager-webhook-service + namespace: {{ .Values.global.spire.namespace }} + path: /validate-spire-spiffe-io-v1alpha1-clusterspiffeid + failurePolicy: Fail + name: vclusterspiffeid.kb.io + rules: + - apiGroups: ["spire.spiffe.io"] + apiVersions: ["v1alpha1"] + operations: ["CREATE", "UPDATE"] + resources: ["clusterspiffeids"] + sideEffects: None + - admissionReviewVersions: ["v1"] + clientConfig: + service: + name: spire-controller-manager-webhook-service + namespace: {{ .Values.global.spire.namespace }} + path: /validate-spire-spiffe-io-v1alpha1-clusterstaticentry + failurePolicy: Fail + name: clusterstaticentry.kb.io + rules: + - apiGroups: ["spire.spiffe.io"] + apiVersions: ["v1alpha1"] + operations: ["CREATE", "UPDATE"] + resources: ["clusterstaticentries"] + sideEffects: None diff --git a/helm-charts/charts/spire/templates/spire-server.yaml b/helm-charts/charts/spire/templates/spire-server.yaml new file mode 100644 index 0000000..9c43607 --- /dev/null +++ b/helm-charts/charts/spire/templates/spire-server.yaml @@ -0,0 +1,265 @@ +# ServiceAccount used by the SPIRE server. +apiVersion: v1 +kind: ServiceAccount +metadata: + name: spire-server + namespace: {{ .Values.global.spire.namespace }} + +--- + +# Required cluster role to allow spire-server to query k8s API server +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: spire-server-cluster-role +rules: + - apiGroups: [""] + resources: ["nodes"] + verbs: ["get"] + # allow TokenReview requests (to verify service account tokens for PSAT + # attestation) + - apiGroups: ["authentication.k8s.io"] + resources: ["tokenreviews"] + verbs: ["get", "create"] + +--- + +# Binds above cluster role to spire-server service account +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: spire-server-cluster-role-binding + namespace: {{ .Values.global.spire.namespace }} +subjects: + - kind: ServiceAccount + name: spire-server + namespace: {{ .Values.global.spire.namespace }} +roleRef: + kind: ClusterRole + name: spire-server-cluster-role + apiGroup: rbac.authorization.k8s.io + +--- + +# Role for the SPIRE server +kind: Role +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: spire-server-role + namespace: {{ .Values.global.spire.namespace }} +rules: + # allow "get" access to pods (to resolve selectors for PSAT attestation) + - apiGroups: [""] + resources: ["pods"] + verbs: ["get"] + # allow access to "get" and "patch" the spire-bundle ConfigMap (for SPIRE + # agent bootstrapping, see the spire-bundle ConfigMap below) + - apiGroups: [""] + resources: ["configmaps"] + resourceNames: ["spire-bundle"] + verbs: ["get", "patch"] + +--- + +# RoleBinding granting the spire-server-role to the SPIRE server +# service account. +kind: RoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: spire-server-role-binding + namespace: {{ .Values.global.spire.namespace }} +subjects: + - kind: ServiceAccount + name: spire-server + namespace: {{ .Values.global.spire.namespace }} +roleRef: + kind: Role + name: spire-server-role + apiGroup: rbac.authorization.k8s.io + +--- + +# ConfigMap containing the latest trust bundle for the trust domain. It is +# updated by SPIRE using the k8sbundle notifier plugin. SPIRE agents mount +# this config map and use the certificate to bootstrap trust with the SPIRE +# server during attestation. +apiVersion: v1 +kind: ConfigMap +metadata: + name: spire-bundle + namespace: {{ .Values.global.spire.namespace }} + +--- + +# ConfigMap containing the SPIRE server configuration. +apiVersion: v1 +kind: ConfigMap +metadata: + name: spire-server + namespace: {{ .Values.global.spire.namespace }} +data: + server.conf: | + server { + bind_address = "0.0.0.0" + bind_port = "8081" + trust_domain = "aegis.ist" + data_dir = "/run/spire/server/data" + log_level = "DEBUG" + federation { + bundle_endpoint { + address = "0.0.0.0" + port = 8443 + } + } + } + + plugins { + DataStore "sql" { + plugin_data { + database_type = "sqlite3" + connection_string = "/run/spire/server/data/datastore.sqlite3" + } + } + + NodeAttestor "k8s_psat" { + plugin_data { + clusters = { + "aegis-cluster" = { + service_account_allow_list = ["{{ .Values.global.spire.namespace }}:spire-agent"] + } + } + } + } + + KeyManager "disk" { + plugin_data { + keys_path = "/run/spire/server/data/keys.json" + } + } + + Notifier "k8sbundle" { + plugin_data { + namespace = "{{ .Values.global.spire.namespace }}" + } + } + } + + health_checks { + listener_enabled = true + bind_address = "0.0.0.0" + bind_port = "8080" + live_path = "/live" + ready_path = "/ready" + } + +--- + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: spire-server + namespace: {{ .Values.global.spire.namespace }} + labels: + app: spire-server +spec: + replicas: 1 + selector: + matchLabels: + app: spire-server + template: + metadata: + namespace: {{ .Values.global.spire.namespace }} + labels: + app: spire-server + spec: + serviceAccountName: spire-server + shareProcessNamespace: true + containers: + - name: spire-server + image: {{ .Values.global.images.spireServer.repository }}:{{ .Values.global.images.spireServer.tag }} + imagePullPolicy: {{ .Values.global.images.spireServer.pullPolicy }} + args: ["-config", "/run/spire/server/config/server.conf"] + ports: + - containerPort: 8081 + volumeMounts: + - name: spire-config + mountPath: /run/spire/server/config + readOnly: true + - name: spire-server-socket + mountPath: /tmp/spire-server/private + - name: spire-controller-manager + image: {{ .Values.global.images.spireControllerManager.repository }}:{{ .Values.global.images.spireControllerManager.tag }} + imagePullPolicy: {{ .Values.global.images.spireControllerManager.pullPolicy }} + ports: + - containerPort: 9443 + args: + - "--config=spire-controller-manager-config.yaml" + volumeMounts: + - name: spire-server-socket + mountPath: /spire-server + readOnly: true + - name: spire-controller-manager-config + mountPath: /spire-controller-manager-config.yaml + subPath: spire-controller-manager-config.yaml + volumes: + - name: spire-config + configMap: + name: spire-server + - name: spire-server-socket + emptyDir: {} + - name: spire-controller-manager-config + configMap: + name: spire-controller-manager-config + +--- + +# Service definition for SPIRE server defining the gRPC port. +apiVersion: v1 +kind: Service +metadata: + name: spire-server + namespace: {{ .Values.global.spire.namespace }} +spec: + type: NodePort + ports: + - name: api + port: 8081 + targetPort: 8081 + protocol: TCP + selector: + app: spire-server + +--- + +# Service definition for SPIRE server bundle endpoint +apiVersion: v1 +kind: Service +metadata: + name: spire-server-bundle-endpoint + namespace: {{ .Values.global.spire.namespace }} +spec: + type: NodePort + ports: + - name: api + port: 8443 + protocol: TCP + selector: + app: spire-server + + +--- +# +# Service definition for SPIRE controller manager webhook +apiVersion: v1 +kind: Service +metadata: + name: spire-controller-manager-webhook-service + namespace: {{ .Values.global.spire.namespace }} +spec: + ports: + - port: 443 + protocol: TCP + targetPort: 9443 + selector: + app: spire-server + diff --git a/helm-charts/charts/spire/values.yaml b/helm-charts/charts/spire/values.yaml new file mode 100644 index 0000000..cca0bcb --- /dev/null +++ b/helm-charts/charts/spire/values.yaml @@ -0,0 +1,50 @@ +# Default values for spire. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +replicaCount: 1 + +imagePullSecrets: [] +nameOverride: "" +fullnameOverride: "" + +serviceAccount: + # Specifies whether a service account should be created + create: true + # Annotations to add to the service account + annotations: {} + # The name of the service account to use. + # If not set and create is true, a name is generated using the fullname template + name: "" + +podAnnotations: {} + +podSecurityContext: {} + # fsGroup: 2000 + +securityContext: {} + # capabilities: + # drop: + # - ALL + # readOnlyRootFilesystem: true + # runAsNonRoot: true + # runAsUser: 1000 + +resources: {} + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + +autoscaling: + enabled: false + minReplicas: 1 + maxReplicas: 100 + targetCPUUtilizationPercentage: 80 + # targetMemoryUtilizationPercentage: 80 diff --git a/helm-charts/crds/spire.spiffe.io_clusterfederatedtrustdomains.yaml b/helm-charts/crds/spire.spiffe.io_clusterfederatedtrustdomains.yaml new file mode 100644 index 0000000..f9c0f95 --- /dev/null +++ b/helm-charts/crds/spire.spiffe.io_clusterfederatedtrustdomains.yaml @@ -0,0 +1,95 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.8.0 + creationTimestamp: null + name: clusterfederatedtrustdomains.spire.spiffe.io +spec: + group: spire.spiffe.io + names: + kind: ClusterFederatedTrustDomain + listKind: ClusterFederatedTrustDomainList + plural: clusterfederatedtrustdomains + singular: clusterfederatedtrustdomain + scope: Cluster + versions: + - additionalPrinterColumns: + - jsonPath: .spec.trustDomain + name: Trust Domain + type: string + - jsonPath: .spec.bundleEndpointURL + name: Endpoint URL + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: ClusterFederatedTrustDomain is the Schema for the clusterfederatedtrustdomains + API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: ClusterFederatedTrustDomainSpec defines the desired state + of ClusterFederatedTrustDomain + properties: + bundleEndpointProfile: + description: BundleEndpointProfile is the profile for the bundle endpoint. + properties: + endpointSPIFFEID: + description: EndpointSPIFFEID is the SPIFFE ID of the bundle endpoint. + It is required for the "https_spiffe" profile. + type: string + type: + description: Type is the type of the bundle endpoint profile. + enum: + - https_spiffe + - https_web + type: string + required: + - type + type: object + bundleEndpointURL: + description: BundleEndpointURL is the URL of the bundle endpoint. + It must be an HTTPS URL and cannot contain userinfo (i.e. username/password). + type: string + trustDomain: + description: TrustDomain is the name of the trust domain to federate + with (e.g. example.org) + pattern: '[a-z0-9._-]{1,255}' + type: string + trustDomainBundle: + description: TrustDomainBundle is the contents of the bundle for the + referenced trust domain. This field is optional when the resource + is created. + type: string + required: + - bundleEndpointProfile + - bundleEndpointURL + - trustDomain + type: object + status: + description: ClusterFederatedTrustDomainStatus defines the observed state + of ClusterFederatedTrustDomain + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] diff --git a/helm-charts/crds/spire.spiffe.io_clusterspiffeids.yaml b/helm-charts/crds/spire.spiffe.io_clusterspiffeids.yaml new file mode 100644 index 0000000..7e6293a --- /dev/null +++ b/helm-charts/crds/spire.spiffe.io_clusterspiffeids.yaml @@ -0,0 +1,221 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.8.0 + creationTimestamp: null + name: clusterspiffeids.spire.spiffe.io +spec: + group: spire.spiffe.io + names: + kind: ClusterSPIFFEID + listKind: ClusterSPIFFEIDList + plural: clusterspiffeids + singular: clusterspiffeid + scope: Cluster + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: ClusterSPIFFEID is the Schema for the clusterspiffeids API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: ClusterSPIFFEIDSpec defines the desired state of ClusterSPIFFEID + properties: + admin: + description: Admin indicates whether or not the SVID can be used to + access the SPIRE administrative APIs. Extra care should be taken + to only apply this SPIFFE ID to admin workloads. + type: boolean + dnsNameTemplates: + description: DNSNameTemplate represents templates for extra DNS names + that are applicable to SVIDs minted for this ClusterSPIFFEID. The + node and pod spec are made available to the template under .NodeSpec, + .PodSpec respectively. + items: + type: string + type: array + federatesWith: + description: FederatesWith is a list of trust domain names that workloads + that obtain this SPIFFE ID will federate with. + items: + type: string + type: array + namespaceSelector: + description: NamespaceSelector selects the namespaces that are targetted + by this CRD. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. + The requirements are ANDed. + items: + description: A label selector requirement is a selector that + contains values, a key, and an operator that relates the key + and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: operator represents a key's relationship to + a set of values. Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of string values. If the + operator is In or NotIn, the values array must be non-empty. + If the operator is Exists or DoesNotExist, the values + array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} pairs. A single + {key,value} in the matchLabels map is equivalent to an element + of matchExpressions, whose key field is "key", the operator + is "In", and the values array contains only "value". The requirements + are ANDed. + type: object + type: object + podSelector: + description: PodSelector selects the pods that are targetted by this + CRD. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. + The requirements are ANDed. + items: + description: A label selector requirement is a selector that + contains values, a key, and an operator that relates the key + and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: operator represents a key's relationship to + a set of values. Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of string values. If the + operator is In or NotIn, the values array must be non-empty. + If the operator is Exists or DoesNotExist, the values + array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} pairs. A single + {key,value} in the matchLabels map is equivalent to an element + of matchExpressions, whose key field is "key", the operator + is "In", and the values array contains only "value". The requirements + are ANDed. + type: object + type: object + spiffeIDTemplate: + description: SPIFFEID is the SPIFFE ID template. The node and pod + spec are made available to the template under .NodeSpec, .PodSpec + respectively. + type: string + ttl: + description: TTL indicates an upper-bound time-to-live for SVIDs minted + for this ClusterSPIFFEID. If unset, a default will be chosen. + type: string + workloadSelectorTemplates: + description: WorkloadSelectorTemplates are templates to produce arbitrary + workload selectors that apply to a given workload before it will + receive this SPIFFE ID. The rendered value is interpreted by SPIRE + and are of the form type:value, where the value may, and often does, + contain semicolons, .e.g., k8s:container-image:docker/hello-world + The node and pod spec are made available to the template under .NodeSpec, + .PodSpec respectively. + items: + type: string + type: array + required: + - spiffeIDTemplate + type: object + status: + description: ClusterSPIFFEIDStatus defines the observed state of ClusterSPIFFEID + properties: + stats: + description: Stats produced by the last entry reconciliation run + properties: + entriesMasked: + description: How many entries were masked by entries for other + ClusterSPIFFEIDs. This happens when one or more ClusterSPIFFEIDs + produce an entry for the same pod with the same set of workload + selectors. + type: integer + entriesToSet: + description: How many entries are to be set for this ClusterSPIFFEID. + In nominal conditions, this should reflect the number of pods + selected, but not always if there were problems encountered + rendering an entry for the pod (RenderFailures) or entries are + masked (EntriesMasked). + type: integer + entryFailures: + description: How many entries were unable to be set due to failures + to create or update the entries via the SPIRE Server API. + type: integer + namespacesIgnored: + description: How many (selected) namespaces were ignored (based + on configuration). + type: integer + namespacesSelected: + description: How many namespaces were selected. + type: integer + podEntryRenderFailures: + description: How many failures were encountered rendering an entry + selected pods. This could be due to either a bad template in + the ClusterSPIFFEID or Pod metadata that when applied to the + template did not produce valid entry values. + type: integer + podsSelected: + description: How many pods were selected out of the namespaces. + type: integer + type: object + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] diff --git a/helm-charts/crds/spire.spiffe.io_clusterstaticentries.yaml b/helm-charts/crds/spire.spiffe.io_clusterstaticentries.yaml new file mode 100644 index 0000000..ffaff61 --- /dev/null +++ b/helm-charts/crds/spire.spiffe.io_clusterstaticentries.yaml @@ -0,0 +1,91 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.11.1 + creationTimestamp: null + name: clusterstaticentries.spire.spiffe.io +spec: + group: spire.spiffe.io + names: + kind: ClusterStaticEntry + listKind: ClusterStaticEntryList + plural: clusterstaticentries + singular: clusterstaticentry + scope: Cluster + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: ClusterStaticEntry is the Schema for the clusterstaticentries + API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: ClusterStaticEntrySpec defines the desired state of ClusterStaticEntry + properties: + admin: + type: boolean + dnsNames: + items: + type: string + type: array + downstream: + type: boolean + federatesWith: + items: + type: string + type: array + hint: + type: string + jwtSVIDTTL: + type: string + parentID: + type: string + selectors: + items: + type: string + type: array + spiffeID: + type: string + x509SVIDTTL: + type: string + required: + - parentID + - selectors + - spiffeID + type: object + status: + description: ClusterStaticEntryStatus defines the observed state of ClusterStaticEntry + properties: + masked: + description: If the static entry was masked by another entry. + type: boolean + rendered: + description: If the static entry rendered properly. + type: boolean + set: + description: If the static entry was successfully created/updated. + type: boolean + required: + - masked + - rendered + - set + type: object + type: object + served: true + storage: true + subresources: + status: {} \ No newline at end of file diff --git a/helm-charts/templates/hook-preinstall-namespace.yaml b/helm-charts/templates/hook-preinstall-namespace.yaml new file mode 100644 index 0000000..a16bd1b --- /dev/null +++ b/helm-charts/templates/hook-preinstall-namespace.yaml @@ -0,0 +1,17 @@ +# +# .-'_.---._'-. +# ||####|(__)|| Protect your secrets, protect your business. +# \\()|##// Secure your sensitive data with Aegis. +# \\ |#// +# .\_/. +# + +apiVersion: v1 +kind: Namespace +metadata: + name: aegis-system + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 4 }} + "helm.sh/hook-weight": "1" + {{- end }} diff --git a/helm-charts/values.yaml b/helm-charts/values.yaml new file mode 100644 index 0000000..b514680 --- /dev/null +++ b/helm-charts/values.yaml @@ -0,0 +1,131 @@ + +global: + deploySpire: true + # possible options for baseImage (distroless, distroless-fips, photon, photon-fips) + baseImage: distroless + registry: aegishub + logLevel: "7" + images: + safe: + distrolessRepository: aegis-ist-safe + distrolessFipsRepository: aegis-ist-fips-safe + photonRepository: aegis-photon-safe + photonFipsRepository: aegis-photon-fips-safe + tag: 0.18.1 + pullPolicy: IfNotPresent + sentinel: + distrolessRepository: aegis-ist-sentinel + distrolessFipsRepository: aegis-ist-fips-sentinel + photonRepository: aegis-photon-sentinel + photonFipsRepository: aegis-photon-fips-sentinel + tag: 0.18.1 + pullPolicy: IfNotPresent + spireAgent: + repository: ghcr.io/spiffe/spire-agent + tag: 1.6.3 + pullPolicy: IfNotPresent + spiffeCsiDriver: + repository: ghcr.io/spiffe/spiffe-csi-driver + tag: 0.2.3 + pullPolicy: IfNotPresent + nodeDriverRegistrar: + repository: registry.k8s.io/sig-storage/csi-node-driver-registrar + tag: v2.7.0 + pullPolicy: IfNotPresent + spireServer: + repository: ghcr.io/spiffe/spire-server + tag: 1.6.3 + pullPolicy: IfNotPresent + spireControllerManager: + repository: ghcr.io/spiffe/spire-controller-manager + tag: nightly + pullPolicy: IfNotPresent + aegis: + namespace: aegis-system + spire: + namespace: spire-system + logLevel: DEBUG + serverPort: 8081 + + +podAnnotations: + "helm.sh/hook": pre-install + +replicaCount: 1 + +image: + repository: nginx + pullPolicy: IfNotPresent + # Overrides the image tag whose default is the chart appVersion. + tag: "" + +imagePullSecrets: [] +nameOverride: "" +fullnameOverride: "" + +serviceAccount: + # Specifies whether a service account should be created + create: true + # Annotations to add to the service account + annotations: {} + # The name of the service account to use. + # If not set and create is true, a name is generated using the fullname template + name: "" + +podAnnotations: {} + +podSecurityContext: {} + # fsGroup: 2000 + +securityContext: {} + # capabilities: + # drop: + # - ALL + # readOnlyRootFilesystem: true + # runAsNonRoot: true + # runAsUser: 1000 + +service: + type: ClusterIP + port: 80 + +ingress: + enabled: false + className: "" + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + hosts: + - host: chart-example.local + paths: + - path: / + pathType: ImplementationSpecific + tls: [] + # - secretName: chart-example-tls + # hosts: + # - chart-example.local + +resources: {} + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + +autoscaling: + enabled: false + minReplicas: 1 + maxReplicas: 100 + targetCPUUtilizationPercentage: 80 + # targetMemoryUtilizationPercentage: 80 + +nodeSelector: {} + +tolerations: [] + +affinity: {}