diff --git a/deployment/helm/node-feature-discovery/templates/spire-agent-cluster-role.yaml b/deployment/helm/node-feature-discovery/templates/spire-agent-cluster-role.yaml new file mode 100644 index 0000000000..d9be601f5c --- /dev/null +++ b/deployment/helm/node-feature-discovery/templates/spire-agent-cluster-role.yaml @@ -0,0 +1,24 @@ +# 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: spire +roleRef: + kind: ClusterRole + name: spire-agent-cluster-role + apiGroup: rbac.authorization.k8s.io diff --git a/deployment/helm/node-feature-discovery/templates/spire-agent-configmap.yaml b/deployment/helm/node-feature-discovery/templates/spire-agent-configmap.yaml new file mode 100644 index 0000000000..27475e0867 --- /dev/null +++ b/deployment/helm/node-feature-discovery/templates/spire-agent-configmap.yaml @@ -0,0 +1,50 @@ +{{- if .Values.spiffe.enable }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: spire-agent +data: + agent.conf: | + agent { + data_dir = "/run/spire" + log_level = "DEBUG" + server_address = "spire-server" + server_port = "8081" + socket_path = "/run/spire/sockets/agent.sock" + trust_bundle_path = "/run/spire/bundle/bundle.crt" + trust_domain = "nfd.com" + } + + plugins { + NodeAttestor "k8s_sat" { + plugin_data { + cluster = "nfd" + } + } + + KeyManager "memory" { + plugin_data { + } + } + + WorkloadAttestor "k8s" { + plugin_data { + skip_kubelet_verification = true + node_name_env = "MY_NODE_NAME" + } + } + + WorkloadAttestor "unix" { + plugin_data { + } + } + } + + health_checks { + listener_enabled = true + bind_address = "0.0.0.0" + bind_port = "8080" + live_path = "/live" + ready_path = "/ready" + } +{{- end }} diff --git a/deployment/helm/node-feature-discovery/templates/spire-agent-daemonset.yaml b/deployment/helm/node-feature-discovery/templates/spire-agent-daemonset.yaml new file mode 100644 index 0000000000..e2cb6599cc --- /dev/null +++ b/deployment/helm/node-feature-discovery/templates/spire-agent-daemonset.yaml @@ -0,0 +1,71 @@ +{{- if .Values.spiffe.enable }} +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: spire-agent + labels: + app: spire-agent +spec: + selector: + matchLabels: + app: spire-agent + template: + metadata: + labels: + app: spire-agent + spec: + hostPID: true + hostNetwork: true + dnsPolicy: ClusterFirstWithHostNet + serviceAccountName: spire-agent + initContainers: + - name: init + # This is a small image with wait-for-it, choose whatever image + # you prefer that waits for a service to be up. This image is built + # from https://github.com/lqhl/wait-for-it + image: cgr.dev/chainguard/wait-for-it + args: ["-t", "30", "spire-server:8081"] + containers: + - name: spire-agent + image: ghcr.io/spiffe/spire-agent:1.5.1 + args: ["-config", "/run/spire/config/agent.conf"] + env: + - name: MY_NODE_NAME + valueFrom: + fieldRef: + fieldPath: status.podIP + volumeMounts: + - name: spire-config + mountPath: /run/spire/config + readOnly: true + - name: spire-bundle + mountPath: /run/spire/bundle + - name: spire-agent-socket + mountPath: /run/spire/sockets + readOnly: false + livenessProbe: + httpGet: + path: /live + port: 8080 + failureThreshold: 2 + initialDelaySeconds: 15 + periodSeconds: 60 + timeoutSeconds: 3 + readinessProbe: + httpGet: + path: /ready + port: 8080 + initialDelaySeconds: 5 + periodSeconds: 5 + volumes: + - name: spire-config + configMap: + name: spire-agent + - name: spire-bundle + configMap: + name: spire-bundle + - name: spire-agent-socket + hostPath: + path: /run/spire/sockets + type: DirectoryOrCreate +{{- end }} diff --git a/deployment/helm/node-feature-discovery/templates/spire-agent-service-account.yaml b/deployment/helm/node-feature-discovery/templates/spire-agent-service-account.yaml new file mode 100644 index 0000000000..9dc8afa57c --- /dev/null +++ b/deployment/helm/node-feature-discovery/templates/spire-agent-service-account.yaml @@ -0,0 +1,6 @@ +{{- if .Values.spiffe.enable }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: spire-agent +{{- end }} diff --git a/deployment/helm/node-feature-discovery/templates/spire-bundle-configmap.yaml b/deployment/helm/node-feature-discovery/templates/spire-bundle-configmap.yaml new file mode 100644 index 0000000000..3b3179b909 --- /dev/null +++ b/deployment/helm/node-feature-discovery/templates/spire-bundle-configmap.yaml @@ -0,0 +1,6 @@ +{{- if .Values.spiffe.enable }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: spire-bundle +{{- end }} diff --git a/deployment/helm/node-feature-discovery/templates/spire-server-cluster-role.yaml b/deployment/helm/node-feature-discovery/templates/spire-server-cluster-role.yaml new file mode 100644 index 0000000000..a5c853f46c --- /dev/null +++ b/deployment/helm/node-feature-discovery/templates/spire-server-cluster-role.yaml @@ -0,0 +1,51 @@ +{{- if .Values.spiffe.enable }} +# Role (namespace scoped) to be able to push certificate bundles to a configmap +kind: Role +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: spire-server-configmap-role + namespace: spire +rules: +- apiGroups: [""] + resources: ["configmaps"] + verbs: ["patch", "get", "list"] +--- +# Binds above role to spire-server service account +kind: RoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: spire-server-configmap-role-binding + namespace: spire +subjects: +- kind: ServiceAccount + name: spire-server + namespace: spire +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: spire-server-configmap-role +--- +# ClusterRole to allow spire-server node attestor to query Token Review API +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: spire-server-trust-role +rules: +- apiGroups: ["authentication.k8s.io"] + resources: ["tokenreviews"] + verbs: ["create"] +--- +# Binds above cluster role to spire-server service account +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: spire-server-trust-role-binding +subjects: +- kind: ServiceAccount + name: spire-server + namespace: spire +roleRef: + kind: ClusterRole + name: spire-server-trust-role + apiGroup: rbac.authorization.k8s.io +{{- end }} diff --git a/deployment/helm/node-feature-discovery/templates/spire-server-configmap.yaml b/deployment/helm/node-feature-discovery/templates/spire-server-configmap.yaml new file mode 100644 index 0000000000..dd3ffba93e --- /dev/null +++ b/deployment/helm/node-feature-discovery/templates/spire-server-configmap.yaml @@ -0,0 +1,63 @@ +{{- if .Values.spiffe.enable }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: spire-server +data: + server.conf: | + server { + bind_address = "0.0.0.0" + bind_port = "8081" + socket_path = "/tmp/spire-server/private/api.sock" + trust_domain = "nfd.com" + data_dir = "/run/spire/data" + log_level = "DEBUG" + #AWS requires the use of RSA. EC cryptography is not supported + ca_key_type = "rsa-2048" + + ca_subject = { + country = ["US"], + organization = ["SPIFFE"], + common_name = "", + } + } + + plugins { + DataStore "sql" { + plugin_data { + database_type = "sqlite3" + connection_string = "/run/spire/data/datastore.sqlite3" + } + } + + NodeAttestor "k8s_sat" { + plugin_data { + clusters = { + "nfd" = { + use_token_review_api_validation = true + service_account_allow_list = ["spire:spire-agent"] + } + } + } + } + + KeyManager "disk" { + plugin_data { + keys_path = "/run/spire/data/keys.json" + } + } + + Notifier "k8sbundle" { + plugin_data { + } + } + } + + health_checks { + listener_enabled = true + bind_address = "0.0.0.0" + bind_port = "8080" + live_path = "/live" + ready_path = "/ready" + } +{{- end }} diff --git a/deployment/helm/node-feature-discovery/templates/spire-server-service-account.yaml b/deployment/helm/node-feature-discovery/templates/spire-server-service-account.yaml new file mode 100644 index 0000000000..f7924166e0 --- /dev/null +++ b/deployment/helm/node-feature-discovery/templates/spire-server-service-account.yaml @@ -0,0 +1,6 @@ +{{- if .Values.spiffe.enable }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: spire-server +{{- end }} diff --git a/deployment/helm/node-feature-discovery/templates/spire-server-service.yaml b/deployment/helm/node-feature-discovery/templates/spire-server-service.yaml new file mode 100644 index 0000000000..fbe64cb304 --- /dev/null +++ b/deployment/helm/node-feature-discovery/templates/spire-server-service.yaml @@ -0,0 +1,15 @@ +{{- if .Values.spiffe.enable }} +apiVersion: v1 +kind: Service +metadata: + name: spire-server +spec: + type: NodePort + ports: + - name: grpc + port: 8081 + targetPort: 8081 + protocol: TCP + selector: + app: spire-server +{{- end }} diff --git a/deployment/helm/node-feature-discovery/templates/spire-server-statefulset.yaml b/deployment/helm/node-feature-discovery/templates/spire-server-statefulset.yaml new file mode 100644 index 0000000000..173b9294be --- /dev/null +++ b/deployment/helm/node-feature-discovery/templates/spire-server-statefulset.yaml @@ -0,0 +1,64 @@ +{{- if .Values.spiffe.enable }} +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: spire-server + labels: + app: spire-server +spec: + replicas: 1 + selector: + matchLabels: + app: spire-server + serviceName: spire-server + template: + metadata: + namespace: spire + labels: + app: spire-server + spec: + serviceAccountName: spire-server + containers: + - name: spire-server + image: ghcr.io/spiffe/spire-server:1.5.1 + args: + - -config + - /run/spire/config/server.conf + ports: + - containerPort: 8081 + volumeMounts: + - name: spire-config + mountPath: /run/spire/config + readOnly: true + - name: spire-data + mountPath: /run/spire/data + readOnly: false + livenessProbe: + httpGet: + path: /live + port: 8080 + failureThreshold: 2 + initialDelaySeconds: 15 + periodSeconds: 60 + timeoutSeconds: 3 + readinessProbe: + httpGet: + path: /ready + port: 8080 + initialDelaySeconds: 5 + periodSeconds: 5 + volumes: + - name: spire-config + configMap: + name: spire-server + volumeClaimTemplates: + - metadata: + name: spire-data + namespace: spire + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi +{{- end }} diff --git a/deployment/helm/node-feature-discovery/values.yaml b/deployment/helm/node-feature-discovery/values.yaml index 29297ad697..6848177644 100644 --- a/deployment/helm/node-feature-discovery/values.yaml +++ b/deployment/helm/node-feature-discovery/values.yaml @@ -13,6 +13,9 @@ namespaceOverride: "" enableNodeFeatureApi: true +spiffe: + enable: true + master: enable: true config: ### @@ -22,6 +25,7 @@ master: # resourceLabels: ["vendor-1.com/feature-1","vendor-2.io/feature-2"] # enableTaints: false # labelWhiteList: "foo" + # enableSpiffe: true # resyncPeriod: "2h" # klog: # addDirHeader: false @@ -142,6 +146,7 @@ worker: # sleepInterval: 60s # featureSources: [all] # labelSources: [all] + # enableSpiffe: true # klog: # addDirHeader: false # alsologtostderr: false diff --git a/deployment/overlays/spiffe/kustomization.yaml b/deployment/overlays/spiffe/kustomization.yaml new file mode 100644 index 0000000000..8212aae303 --- /dev/null +++ b/deployment/overlays/spiffe/kustomization.yaml @@ -0,0 +1,19 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +namespace: node-feature-discovery + +resources: +- spire-agent-cluster-role.yaml +- spire-agent-configmap.yaml +- spire-agent-daemonset.yaml +- spire-agent-service-account.yaml +- spire-bundle-configmap.yaml +- spire-server-cluster-role.yaml +- spire-server-configmap.yaml +- spire-server-service-account.yaml +- spire-server-service.yaml +- spire-server-statefulset.yaml + + + diff --git a/deployment/overlays/spiffe/spire-agent-cluster-role.yaml b/deployment/overlays/spiffe/spire-agent-cluster-role.yaml new file mode 100644 index 0000000000..7401aa6c3e --- /dev/null +++ b/deployment/overlays/spiffe/spire-agent-cluster-role.yaml @@ -0,0 +1,26 @@ +{{- if .Values.spiffe.enable }} +# 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: spire +roleRef: + kind: ClusterRole + name: spire-agent-cluster-role + apiGroup: rbac.authorization.k8s.io +{{- end }} diff --git a/deployment/overlays/spiffe/spire-agent-configmap.yaml b/deployment/overlays/spiffe/spire-agent-configmap.yaml new file mode 100644 index 0000000000..a3c769b520 --- /dev/null +++ b/deployment/overlays/spiffe/spire-agent-configmap.yaml @@ -0,0 +1,48 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: spire-agent +data: + agent.conf: | + agent { + data_dir = "/run/spire" + log_level = "DEBUG" + server_address = "spire-server" + server_port = "8081" + socket_path = "/run/spire/sockets/agent.sock" + trust_bundle_path = "/run/spire/bundle/bundle.crt" + trust_domain = "nfd.com" + } + + plugins { + NodeAttestor "k8s_sat" { + plugin_data { + cluster = "nfd" + } + } + + KeyManager "memory" { + plugin_data { + } + } + + WorkloadAttestor "k8s" { + plugin_data { + skip_kubelet_verification = true + node_name_env = "MY_NODE_NAME" + } + } + + WorkloadAttestor "unix" { + plugin_data { + } + } + } + + health_checks { + listener_enabled = true + bind_address = "0.0.0.0" + bind_port = "8080" + live_path = "/live" + ready_path = "/ready" + } diff --git a/deployment/overlays/spiffe/spire-agent-daemonset.yaml b/deployment/overlays/spiffe/spire-agent-daemonset.yaml new file mode 100644 index 0000000000..5480886ffe --- /dev/null +++ b/deployment/overlays/spiffe/spire-agent-daemonset.yaml @@ -0,0 +1,69 @@ +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: spire-agent + labels: + app: spire-agent +spec: + selector: + matchLabels: + app: spire-agent + template: + metadata: + labels: + app: spire-agent + spec: + hostPID: true + hostNetwork: true + dnsPolicy: ClusterFirstWithHostNet + serviceAccountName: spire-agent + initContainers: + - name: init + # This is a small image with wait-for-it, choose whatever image + # you prefer that waits for a service to be up. This image is built + # from https://github.com/lqhl/wait-for-it + image: cgr.dev/chainguard/wait-for-it + args: ["-t", "30", "spire-server:8081"] + containers: + - name: spire-agent + image: ghcr.io/spiffe/spire-agent:1.5.1 + args: ["-config", "/run/spire/config/agent.conf"] + env: + - name: MY_NODE_NAME + valueFrom: + fieldRef: + fieldPath: status.podIP + volumeMounts: + - name: spire-config + mountPath: /run/spire/config + readOnly: true + - name: spire-bundle + mountPath: /run/spire/bundle + - name: spire-agent-socket + mountPath: /run/spire/sockets + readOnly: false + livenessProbe: + httpGet: + path: /live + port: 8080 + failureThreshold: 2 + initialDelaySeconds: 15 + periodSeconds: 60 + timeoutSeconds: 3 + readinessProbe: + httpGet: + path: /ready + port: 8080 + initialDelaySeconds: 5 + periodSeconds: 5 + volumes: + - name: spire-config + configMap: + name: spire-agent + - name: spire-bundle + configMap: + name: spire-bundle + - name: spire-agent-socket + hostPath: + path: /run/spire/sockets + type: DirectoryOrCreate diff --git a/deployment/overlays/spiffe/spire-agent-service-account.yaml b/deployment/overlays/spiffe/spire-agent-service-account.yaml new file mode 100644 index 0000000000..813ee9ace9 --- /dev/null +++ b/deployment/overlays/spiffe/spire-agent-service-account.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: spire-agent + diff --git a/deployment/overlays/spiffe/spire-bundle-configmap.yaml b/deployment/overlays/spiffe/spire-bundle-configmap.yaml new file mode 100644 index 0000000000..7ad63a5a89 --- /dev/null +++ b/deployment/overlays/spiffe/spire-bundle-configmap.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: spire-bundle diff --git a/deployment/overlays/spiffe/spire-server-cluster-role.yaml b/deployment/overlays/spiffe/spire-server-cluster-role.yaml new file mode 100644 index 0000000000..80fcf4bc09 --- /dev/null +++ b/deployment/overlays/spiffe/spire-server-cluster-role.yaml @@ -0,0 +1,49 @@ +# Role (namespace scoped) to be able to push certificate bundles to a configmap +kind: Role +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: spire-server-configmap-role + namespace: spire +rules: +- apiGroups: [""] + resources: ["configmaps"] + verbs: ["patch", "get", "list"] +--- +# Binds above role to spire-server service account +kind: RoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: spire-server-configmap-role-binding + namespace: spire +subjects: +- kind: ServiceAccount + name: spire-server + namespace: spire +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: spire-server-configmap-role +--- +# ClusterRole to allow spire-server node attestor to query Token Review API +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: spire-server-trust-role +rules: +- apiGroups: ["authentication.k8s.io"] + resources: ["tokenreviews"] + verbs: ["create"] +--- +# Binds above cluster role to spire-server service account +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: spire-server-trust-role-binding +subjects: +- kind: ServiceAccount + name: spire-server + namespace: spire +roleRef: + kind: ClusterRole + name: spire-server-trust-role + apiGroup: rbac.authorization.k8s.io diff --git a/deployment/overlays/spiffe/spire-server-configmap.yaml b/deployment/overlays/spiffe/spire-server-configmap.yaml new file mode 100644 index 0000000000..ab9fea6194 --- /dev/null +++ b/deployment/overlays/spiffe/spire-server-configmap.yaml @@ -0,0 +1,61 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: spire-server +data: + server.conf: | + server { + bind_address = "0.0.0.0" + bind_port = "8081" + socket_path = "/tmp/spire-server/private/api.sock" + trust_domain = "nfd.com" + data_dir = "/run/spire/data" + log_level = "DEBUG" + #AWS requires the use of RSA. EC cryptography is not supported + ca_key_type = "rsa-2048" + + ca_subject = { + country = ["US"], + organization = ["SPIFFE"], + common_name = "", + } + } + + plugins { + DataStore "sql" { + plugin_data { + database_type = "sqlite3" + connection_string = "/run/spire/data/datastore.sqlite3" + } + } + + NodeAttestor "k8s_sat" { + plugin_data { + clusters = { + "nfd" = { + use_token_review_api_validation = true + service_account_allow_list = ["spire:spire-agent"] + } + } + } + } + + KeyManager "disk" { + plugin_data { + keys_path = "/run/spire/data/keys.json" + } + } + + Notifier "k8sbundle" { + plugin_data { + } + } + } + + health_checks { + listener_enabled = true + bind_address = "0.0.0.0" + bind_port = "8080" + live_path = "/live" + ready_path = "/ready" + } diff --git a/deployment/overlays/spiffe/spire-server-service-account.yaml b/deployment/overlays/spiffe/spire-server-service-account.yaml new file mode 100644 index 0000000000..acf9944260 --- /dev/null +++ b/deployment/overlays/spiffe/spire-server-service-account.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: spire-server diff --git a/deployment/overlays/spiffe/spire-server-service.yaml b/deployment/overlays/spiffe/spire-server-service.yaml new file mode 100644 index 0000000000..cf9c1f067e --- /dev/null +++ b/deployment/overlays/spiffe/spire-server-service.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: Service +metadata: + name: spire-server +spec: + type: NodePort + ports: + - name: grpc + port: 8081 + targetPort: 8081 + protocol: TCP + selector: + app: spire-server diff --git a/deployment/overlays/spiffe/spire-server-statefulset.yaml b/deployment/overlays/spiffe/spire-server-statefulset.yaml new file mode 100644 index 0000000000..4a43b7ceef --- /dev/null +++ b/deployment/overlays/spiffe/spire-server-statefulset.yaml @@ -0,0 +1,62 @@ +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: spire-server + labels: + app: spire-server +spec: + replicas: 1 + selector: + matchLabels: + app: spire-server + serviceName: spire-server + template: + metadata: + namespace: spire + labels: + app: spire-server + spec: + serviceAccountName: spire-server + containers: + - name: spire-server + image: ghcr.io/spiffe/spire-server:1.5.1 + args: + - -config + - /run/spire/config/server.conf + ports: + - containerPort: 8081 + volumeMounts: + - name: spire-config + mountPath: /run/spire/config + readOnly: true + - name: spire-data + mountPath: /run/spire/data + readOnly: false + livenessProbe: + httpGet: + path: /live + port: 8080 + failureThreshold: 2 + initialDelaySeconds: 15 + periodSeconds: 60 + timeoutSeconds: 3 + readinessProbe: + httpGet: + path: /ready + port: 8080 + initialDelaySeconds: 5 + periodSeconds: 5 + volumes: + - name: spire-config + configMap: + name: spire-server + volumeClaimTemplates: + - metadata: + name: spire-data + namespace: spire + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi