From f0e5ff0e11dda566444ae0411f8f8cb2a684e3d6 Mon Sep 17 00:00:00 2001 From: Sergio Arroutbi Date: Wed, 24 Jan 2024 13:25:16 +0100 Subject: [PATCH] Create bundle to enable operator-sdk deployment Resolves: #52 Signed-off-by: Sergio Arroutbi --- Makefile | 123 ++++- README.md | 32 ++ bundle.Dockerfile | 21 + ...er-manager-metrics-service_v1_service.yaml | 23 + ...c.authorization.k8s.io_v1_clusterrole.yaml | 17 + ...n-operator-metrics-service_v1_service.yaml | 23 + ...tation-operator.clusterserviceversion.yaml | 251 +++++++++ .../attestation.keylime.dev_agents.yaml | 515 ++++++++++++++++++ bundle/metadata/annotations.yaml | 15 + bundle/tests/scorecard/config.yaml | 70 +++ ...tation-operator.clusterserviceversion.yaml | 251 +++++++++ ...tation-operator.clusterserviceversion.yaml | 81 +++ config/manifests/kustomization.yaml | 27 + config/scorecard/bases/config.yaml | 7 + config/scorecard/kustomization.yaml | 16 + config/scorecard/patches/basic.config.yaml | 10 + config/scorecard/patches/olm.config.yaml | 50 ++ 17 files changed, 1531 insertions(+), 1 deletion(-) create mode 100644 bundle.Dockerfile create mode 100644 bundle/manifests/attestation-operator-controller-manager-metrics-service_v1_service.yaml create mode 100644 bundle/manifests/attestation-operator-metrics-reader_rbac.authorization.k8s.io_v1_clusterrole.yaml create mode 100644 bundle/manifests/attestation-operator-metrics-service_v1_service.yaml create mode 100644 bundle/manifests/attestation-operator.clusterserviceversion.yaml create mode 100644 bundle/manifests/attestation.keylime.dev_agents.yaml create mode 100644 bundle/metadata/annotations.yaml create mode 100644 bundle/tests/scorecard/config.yaml create mode 100644 config/manifests/attestation-operator.clusterserviceversion.yaml create mode 100644 config/manifests/bases/attestation-operator.clusterserviceversion.yaml create mode 100644 config/manifests/kustomization.yaml create mode 100644 config/scorecard/bases/config.yaml create mode 100644 config/scorecard/kustomization.yaml create mode 100644 config/scorecard/patches/basic.config.yaml create mode 100644 config/scorecard/patches/olm.config.yaml diff --git a/Makefile b/Makefile index f89398c..d3866c1 100644 --- a/Makefile +++ b/Makefile @@ -21,7 +21,8 @@ BUILD_DATE = $(shell date -u -Iseconds) DOCKER_BUILDX_FLAGS ?= #DOCKER_PLATFORMS ?= linux/amd64,linux/arm64 DOCKER_PLATFORMS ?= linux/amd64 -DOCKER_TAG ?= quay.io/keylime/keylime_attestation_operator:$(VERSION) +DOCKER_NO_VERSION_TAG ?= quay.io/keylime/keylime_attestation_operator +DOCKER_TAG ?= $(DOCKER_NO_VERSION_TAG):$(VERSION) # helm chart version must be semver 2 compliant HELM_CHART_REPO ?= ghcr.io/keylime/helm-charts @@ -52,6 +53,53 @@ else GOBIN=$(shell go env GOBIN) endif +# Bundle version does not accept "latest", it must contain something similar to vMajor.Minor.Patch +BUNDLE_VERSION ?= $(VERSION) +ifeq ($(BUNDLE_VERSION),latest) + BUNDLE_VERSION=$(HELM_CHART_CONTROLLER_VERSION) +endif + +# Bundle related information +# CHANNELS define the bundle channels used in the bundle. +# Add a new line here if you would like to change its default config. (E.g CHANNELS = "candidate,fast,stable") +# To re-generate a bundle for other specific channels without changing the standard setup, you can: +# - use the CHANNELS as arg of the bundle target (e.g make bundle CHANNELS=candidate,fast,stable) +# - use environment variables to overwrite this value (e.g export CHANNELS="candidate,fast,stable") +ifneq ($(origin CHANNELS), undefined) +BUNDLE_CHANNELS := --channels=$(CHANNELS) +endif + +# DEFAULT_CHANNEL defines the default channel used in the bundle. +# Add a new line here if you would like to change its default config. (E.g DEFAULT_CHANNEL = "stable") +# To re-generate a bundle for any other default channel without changing the default setup, you can: +# - use the DEFAULT_CHANNEL as arg of the bundle target (e.g make bundle DEFAULT_CHANNEL=stable) +# - use environment variables to overwrite this value (e.g export DEFAULT_CHANNEL="stable") +DEFAULT_CHANNEL ?= stable +ifneq ($(origin DEFAULT_CHANNEL), undefined) +BUNDLE_DEFAULT_CHANNEL := --default-channel=$(DEFAULT_CHANNEL) +endif +BUNDLE_METADATA_OPTS ?= $(BUNDLE_CHANNELS) $(BUNDLE_DEFAULT_CHANNEL) + +# BUNDLE_IMG defines the image:tag used for the bundle. +# You can use it as an arg. (E.g make bundle-build BUNDLE_IMG=/:) +BUNDLE_IMG ?= $(DOCKER_NO_VERSION_TAG)-bundle:$(BUNDLE_VERSION) + +# BUNDLE_GEN_FLAGS are the flags passed to the operator-sdk generate bundle command +BUNDLE_GEN_FLAGS ?= -q --overwrite --version $(BUNDLE_VERSION) $(BUNDLE_METADATA_OPTS) + +# USE_IMAGE_DIGESTS defines if images are resolved via tags or digests +# You can enable this value if you would like to use SHA Based Digests +# To enable set flag to true +USE_IMAGE_DIGESTS ?= false +ifeq ($(USE_IMAGE_DIGESTS), true) + BUNDLE_GEN_FLAGS += --use-image-digests +endif + +# Set the Operator SDK version to use. By default, what is installed on the system is used. +# This is useful for CI or a project to utilize a specific version of the operator-sdk toolkit. +OPERATOR_SDK_VERSION ?= v1.33.0 + + ##@ General # The help target prints out all targets with their descriptions organized @@ -318,3 +366,76 @@ helm-controller-clean: .PHONY: helm-controller-push helm-controller-push: helm-controller ## Builds AND pushes the keylime-controller helm chart helm push $(BUILD_ARTIFACTS_DIR)/keylime-controller-$(HELM_CHART_CONTROLLER_VERSION).tgz oci://$(HELM_CHART_REPO) + +.PHONY: operator-sdk +OPERATOR_SDK ?= $(LOCALBIN)/operator-sdk +operator-sdk: ## Download operator-sdk locally if necessary. +ifeq (,$(wildcard $(OPERATOR_SDK))) +ifeq (, $(shell which operator-sdk 2>/dev/null)) + @{ \ + set -e ;\ + mkdir -p $(dir $(OPERATOR_SDK)) ;\ + OS=$(shell go env GOOS) && ARCH=$(shell go env GOARCH) && \ + curl -sSLo $(OPERATOR_SDK) https://github.com/operator-framework/operator-sdk/releases/download/$(OPERATOR_SDK_VERSION)/operator-sdk_$${OS}_$${ARCH} ;\ + chmod +x $(OPERATOR_SDK) ;\ + } +else +OPERATOR_SDK = $(shell which operator-sdk) +endif +endif + +.PHONY: bundle +bundle: manifests kustomize operator-sdk ## Generate bundle manifests and metadata, then validate generated files. + $(OPERATOR_SDK) generate kustomize manifests -q + cd config/manager && $(KUSTOMIZE) edit set image controller=$(DOCKER_TAG) + $(KUSTOMIZE) build config/manifests | $(OPERATOR_SDK) generate bundle $(BUNDLE_GEN_FLAGS) + $(OPERATOR_SDK) bundle validate ./bundle + +.PHONY: bundle-build +bundle-build: ## Build the bundle image. + docker build -f bundle.Dockerfile -t $(BUNDLE_IMG) . + +.PHONY: bundle-push +bundle-push: ## Push the bundle image. + $(MAKE) docker-push DOCKER_TAG=$(BUNDLE_IMG) + +.PHONY: opm +OPM = ./bin/opm +opm: ## Download opm locally if necessary. +ifeq (,$(wildcard $(OPM))) +ifeq (,$(shell which opm 2>/dev/null)) + @{ \ + set -e ;\ + mkdir -p $(dir $(OPM)) ;\ + OS=$(shell go env GOOS) && ARCH=$(shell go env GOARCH) && \ + curl -sSLo $(OPM) https://github.com/operator-framework/operator-registry/releases/download/v1.23.0/$${OS}-$${ARCH}-opm ;\ + chmod +x $(OPM) ;\ + } +else +OPM = $(shell which opm) +endif +endif + +# A comma-separated list of bundle images (e.g. make catalog-build BUNDLE_IMGS=example.com/operator-bundle:v0.1.0,example.com/operator-bundle:v0.2.0). +# These images MUST exist in a registry and be pull-able. +BUNDLE_IMGS ?= $(BUNDLE_IMG) + +# The image tag given to the resulting catalog image (e.g. make catalog-build CATALOG_IMG=example.com/operator-catalog:v0.2.0). +CATALOG_IMG ?= $(IMAGE_TAG_BASE)-catalog:v$(VERSION) + +# Set CATALOG_BASE_IMG to an existing catalog image tag to add $BUNDLE_IMGS to that image. +ifneq ($(origin CATALOG_BASE_IMG), undefined) +FROM_INDEX_OPT := --from-index $(CATALOG_BASE_IMG) +endif + +# Build a catalog image by adding bundle images to an empty catalog using the operator package manager tool, 'opm'. +# This recipe invokes 'opm' in 'semver' bundle add mode. For more information on add modes, see: +# https://github.com/operator-framework/community-operators/blob/7f1438c/docs/packaging-operator.md#updating-your-existing-operator +.PHONY: catalog-build +catalog-build: opm ## Build a catalog image. + $(OPM) index add --container-tool docker --mode semver --tag $(CATALOG_IMG) --bundles $(BUNDLE_IMGS) $(FROM_INDEX_OPT) + +# Push the catalog image. +.PHONY: catalog-push +catalog-push: ## Push a catalog image. + $(MAKE) docker-push DOCKER_TAG=$(CATALOG_IMG) diff --git a/README.md b/README.md index da6b311..434558d 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,38 @@ d) `make helm-deploy` will deploy an initial barebones (but functional) deployme e) `make helm-undeploy` will remove the whole deployment +## Deploying a controller + +### Deployment/cleanup of the operator through operator-sdk +Operator can be deployed with operator-sdk, as it has olm/bundle support. +To do so, you will need `operator-sdk` to be installed. +Follow next instructions to compile, upload and deploy through operator-sdk: +* Compile controller: +```bash +make docker-build docker-push DOCKER_TAG=quay.io/{quay_user}/attestation-operator:v0.1.0 +``` +* Generate bundle and push it to registry: +```bash +make bundle DOCKER_TAG=quay.io/{quay_user_here}/attestation-operator:v0.1.0 +make bundle-build bundle-push BUNDLE_IMG="quay.io/{quay_user}/attestation-operator-bundle:v0.1.0" +``` +* Deploy through `operator-sdk` tool: +```bash +operator-sdk run bundle quay.io/{quay_user}/attestation-operator-bundle:v0.1.0 +``` +* In case operator needs to be deployed in a particular namespace, use `--namespace` tool: +```bash +operator-sdk run bundle quay.io/{quay_user}/attestation-operator-bundle:v0.1.0 --namespace keylime +``` +* For operator cleanup, just execute `cleanup` operator-sdk option: +```bash +operator-sdk cleanup attestation-operator +``` +* In case a namespace was provided for deployment, it must be similarly used on cleanup: +```bash +operator-sdk cleanup attestation-operator --namespace keylime +``` + ## Customizing the deployment. By default, the `Makefile` looks for a yaml file on the path set by diff --git a/bundle.Dockerfile b/bundle.Dockerfile new file mode 100644 index 0000000..b8a4e53 --- /dev/null +++ b/bundle.Dockerfile @@ -0,0 +1,21 @@ +FROM scratch + +# Core bundle labels. +LABEL operators.operatorframework.io.bundle.mediatype.v1=registry+v1 +LABEL operators.operatorframework.io.bundle.manifests.v1=manifests/ +LABEL operators.operatorframework.io.bundle.metadata.v1=metadata/ +LABEL operators.operatorframework.io.bundle.package.v1=attestation-operator +LABEL operators.operatorframework.io.bundle.channels.v1=alpha +LABEL operators.operatorframework.io.bundle.channel.default.v1=stable +LABEL operators.operatorframework.io.metrics.builder=operator-sdk-v1.33.0 +LABEL operators.operatorframework.io.metrics.mediatype.v1=metrics+v1 +LABEL operators.operatorframework.io.metrics.project_layout=go.kubebuilder.io/v4 + +# Labels for testing. +LABEL operators.operatorframework.io.test.mediatype.v1=scorecard+v1 +LABEL operators.operatorframework.io.test.config.v1=tests/scorecard/ + +# Copy files to locations specified by labels. +COPY bundle/manifests /manifests/ +COPY bundle/metadata /metadata/ +COPY bundle/tests/scorecard /tests/scorecard/ diff --git a/bundle/manifests/attestation-operator-controller-manager-metrics-service_v1_service.yaml b/bundle/manifests/attestation-operator-controller-manager-metrics-service_v1_service.yaml new file mode 100644 index 0000000..be62a59 --- /dev/null +++ b/bundle/manifests/attestation-operator-controller-manager-metrics-service_v1_service.yaml @@ -0,0 +1,23 @@ +apiVersion: v1 +kind: Service +metadata: + creationTimestamp: null + labels: + app.kubernetes.io/component: kube-rbac-proxy + app.kubernetes.io/created-by: attestation-operator + app.kubernetes.io/instance: controller-manager-metrics-service + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: service + app.kubernetes.io/part-of: attestation-operator + control-plane: controller-manager + name: attestation-operator-controller-manager-metrics-service +spec: + ports: + - name: https + port: 8443 + protocol: TCP + targetPort: https + selector: + control-plane: controller-manager +status: + loadBalancer: {} diff --git a/bundle/manifests/attestation-operator-metrics-reader_rbac.authorization.k8s.io_v1_clusterrole.yaml b/bundle/manifests/attestation-operator-metrics-reader_rbac.authorization.k8s.io_v1_clusterrole.yaml new file mode 100644 index 0000000..8b34178 --- /dev/null +++ b/bundle/manifests/attestation-operator-metrics-reader_rbac.authorization.k8s.io_v1_clusterrole.yaml @@ -0,0 +1,17 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + creationTimestamp: null + labels: + app.kubernetes.io/component: kube-rbac-proxy + app.kubernetes.io/created-by: attestation-operator + app.kubernetes.io/instance: metrics-reader + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: clusterrole + app.kubernetes.io/part-of: attestation-operator + name: attestation-operator-metrics-reader +rules: +- nonResourceURLs: + - /metrics + verbs: + - get diff --git a/bundle/manifests/attestation-operator-metrics-service_v1_service.yaml b/bundle/manifests/attestation-operator-metrics-service_v1_service.yaml new file mode 100644 index 0000000..37399dd --- /dev/null +++ b/bundle/manifests/attestation-operator-metrics-service_v1_service.yaml @@ -0,0 +1,23 @@ +apiVersion: v1 +kind: Service +metadata: + creationTimestamp: null + labels: + app.kubernetes.io/component: kube-rbac-proxy + app.kubernetes.io/created-by: attestation-operator + app.kubernetes.io/instance: metrics-service + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: service + app.kubernetes.io/part-of: attestation-operator + control-plane: controller-manager + name: attestation-operator-metrics-service +spec: + ports: + - name: https + port: 8443 + protocol: TCP + targetPort: https + selector: + control-plane: controller-manager +status: + loadBalancer: {} diff --git a/bundle/manifests/attestation-operator.clusterserviceversion.yaml b/bundle/manifests/attestation-operator.clusterserviceversion.yaml new file mode 100644 index 0000000..bd64242 --- /dev/null +++ b/bundle/manifests/attestation-operator.clusterserviceversion.yaml @@ -0,0 +1,251 @@ +apiVersion: operators.coreos.com/v1alpha1 +kind: ClusterServiceVersion +metadata: + annotations: + alm-examples: |- + [ + { + "apiVersion": "attestation.keylime.dev/v1alpha1", + "kind": "Agent", + "metadata": { + "labels": { + "app.kubernetes.io/created-by": "attestation-operator", + "app.kubernetes.io/instance": "agent-sample", + "app.kubernetes.io/managed-by": "kustomize", + "app.kubernetes.io/name": "agent", + "app.kubernetes.io/part-of": "attestation-operator" + }, + "name": "agent-sample" + }, + "spec": null + } + ] + capabilities: Basic Install + createdAt: "2024-01-31T12:38:03Z" + operators.operatorframework.io/builder: operator-sdk-v1.33.0 + operators.operatorframework.io/project_layout: go.kubebuilder.io/v4 + name: attestation-operator.v0.1.0 + namespace: placeholder +spec: + apiservicedefinitions: {} + customresourcedefinitions: + owned: + - kind: Agent + name: agents.attestation.keylime.dev + version: v1alpha1 + description: Operator SDK based Attestation Operator + displayName: osdk-attestation-operator + icon: + - base64data: "" + mediatype: "" + install: + spec: + clusterPermissions: + - rules: + - apiGroups: + - attestation.keylime.dev + resources: + - agents + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: + - attestation.keylime.dev + resources: + - agents/finalizers + verbs: + - update + - apiGroups: + - attestation.keylime.dev + resources: + - agents/status + verbs: + - get + - patch + - update + - apiGroups: + - "" + resources: + - pods + verbs: + - get + - list + - watch + - apiGroups: + - "" + resources: + - secrets + verbs: + - get + - list + - watch + - apiGroups: + - authentication.k8s.io + resources: + - tokenreviews + verbs: + - create + - apiGroups: + - authorization.k8s.io + resources: + - subjectaccessreviews + verbs: + - create + serviceAccountName: attestation-operator-controller-manager + deployments: + - label: + app.kubernetes.io/component: manager + app.kubernetes.io/created-by: attestation-operator + app.kubernetes.io/instance: controller-manager + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: deployment + app.kubernetes.io/part-of: attestation-operator + control-plane: controller-manager + name: attestation-operator-controller-manager + spec: + replicas: 1 + selector: + matchLabels: + control-plane: controller-manager + strategy: {} + template: + metadata: + annotations: + kubectl.kubernetes.io/default-container: manager + labels: + control-plane: controller-manager + spec: + containers: + - args: + - --leader-elect + command: + - /bin/attestation-operator + env: + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: KEYLIME_REGISTRAR_URL + value: https://10.110.133.5:8891/ + - name: KEYLIME_VERIFIER_URL + value: https://10.110.231.226:8881/ + - name: KEYLIME_CLIENT_KEY + value: /var/lib/keylime/cv_ca/client-private.pem + - name: KEYLIME_CLIENT_CERT + value: /var/lib/keylime/cv_ca/client-cert.crt + - name: KEYLIME_REGISTRAR_SYNCHRONIZER_INTERVAL_DURATION + value: 10s + - name: KEYLIME_AGENT_RECONCILE_INTERVAL_DURATION + value: 5s + - name: KEYLIME_TPM_CERT_STORE + value: /var/lib/keylime/tpm_cert_store + - name: KEYLIME_SECURE_PAYLOAD_DIR + value: /var/lib/keylime/secure_payload + image: quay.io/sec-eng-special/attestation-operator:v0.1.0 + livenessProbe: + httpGet: + path: /healthz + port: 8081 + initialDelaySeconds: 15 + periodSeconds: 20 + name: manager + readinessProbe: + httpGet: + path: /readyz + port: 8081 + initialDelaySeconds: 5 + periodSeconds: 10 + resources: + limits: + cpu: 500m + memory: 128Mi + requests: + cpu: 10m + memory: 64Mi + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + volumeMounts: + - mountPath: /var/lib/keylime/cv_ca/ + name: certs + readOnly: true + - mountPath: /var/lib/keylime/tpm_cert_store + name: tpm-cert-store + readOnly: true + securityContext: + runAsNonRoot: true + serviceAccountName: attestation-operator-controller-manager + terminationGracePeriodSeconds: 10 + volumes: + - name: certs + secret: + defaultMode: 420 + secretName: hhkl-keylime-certs + - name: tpm-cert-store + secret: + defaultMode: 420 + secretName: keylime-swtpm-cert-store + permissions: + - 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 + serviceAccountName: attestation-operator-controller-manager + strategy: deployment + installModes: + - supported: false + type: OwnNamespace + - supported: false + type: SingleNamespace + - supported: false + type: MultiNamespace + - supported: true + type: AllNamespaces + keywords: + - attestation + - security + links: + - name: Osdk Attestation Operator + url: https://osdk-attestation-operator.domain + maintainers: + - email: sarroutb@redhat.com + name: Sergio Arroutbi + maturity: alpha + provider: + name: Red Hat Inc + version: 0.1.0 diff --git a/bundle/manifests/attestation.keylime.dev_agents.yaml b/bundle/manifests/attestation.keylime.dev_agents.yaml new file mode 100644 index 0000000..6e27d4a --- /dev/null +++ b/bundle/manifests/attestation.keylime.dev_agents.yaml @@ -0,0 +1,515 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.12.0 + creationTimestamp: null + name: agents.attestation.keylime.dev +spec: + group: attestation.keylime.dev + names: + kind: Agent + listKind: AgentList + plural: agents + singular: agent + scope: Cluster + versions: + - additionalPrinterColumns: + - jsonPath: .status.pod + name: Pod + type: string + - jsonPath: .status.node + name: Node + type: string + - jsonPath: .spec.verifierName + name: Verifier + type: string + - jsonPath: .status.phase + name: Phase + type: string + - jsonPath: .status.verifier.operationalState + name: State + type: string + - format: date-time + jsonPath: .status.verifier.lastSuccessfulAttestation + name: Last Successful Attestation + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: Agent is the Schema for the agents 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: AgentSpec defines the desired state of Agent + properties: + ekCertificateStore: + description: EKCertificateStore contains all the configuration settings + for the verification of the EK certificate of the agent. + properties: + enableVerification: + description: EnableVerification turns on EK certificate verification. + If this is enabled, you must also set either the SecretName + below, or the ControllerDirectoryPath. + type: boolean + secretName: + description: "SecretName is the name of a secret which should + contain CA certificates that should be used to verify the EK + certificate of the agent if EnableVerification is set. \n If + EnableVerification is true, but SecretName is empty, then the + controller will fall back to try to use the CA certificates + as set with the optional KEYLIME_TPM_CERT_STORE setting. NOTE: + It is recommended to use a secret though. However, in cases + where people do not feel comfortable to give the service account + of the controller access to secrets, or want to bake in the + secure payloads into the controller image or mount a volume/secret + into the controller for that purpose, this fallback mechanism + provides a way to accomodate that." + type: string + required: + - enableVerification + - secretName + type: object + securePayload: + description: SecurePayload contains all the configuration settings + for the Secure Payload mechanism of Keylime. + properties: + agentVerify: + description: 'AgentVerify will additionally request to verify + with the agent that after the agent has been added to the verifier + that the bootstrap keys were delivered and derived successfully. + This means that the secure payload could technically be decrypted + by the agent. However, this does not verify unpacking of the + payload, just that the correct keys were derived on the agent. + NOTE: the verification mechanism fails at times, and is also + optional in the keylime_tenant CLI, so we make this switchable + here as well.' + type: boolean + enableSecurePayload: + description: EnableSecurePayload turns on the Secure Payload delivery + of Keylime. It happens during the process when an agent is added + to a verifier. + type: boolean + secretName: + description: "SecretName is the name of a secret which contents + should be delivered to the agent via the Secure Payload mechanism. + NOTE: If there is a change in this value after the agent has + been added to a verifier, this will effectively delete the agent + from the verifier and add it again! \n If EnableSecurePayload + is true, but SecretName is empty, then the controller will fall + back to try to use a directory as set with the optional KEYLIME_SECURE_PAYLOAD_DIR + setting. NOTE: It is recommended to use a secret though. However, + in cases where people do not feel comfortable to give the service + account of the controller access to secrets, or want to bake + in the secure payloads into the controller image or mount a + volume/secret into the controller for that purpose, this fallback + mechanism provides a way to accomodate that." + type: string + required: + - agentVerify + - enableSecurePayload + - secretName + type: object + verifierName: + description: VerifierName is the verifier that the agent should be + scheduled on. The expected format is "IP:port" or "Host:port". + type: string + required: + - ekCertificateStore + - securePayload + - verifierName + type: object + status: + description: AgentStatus defines the observed state of Agent + properties: + ekCertificate: + description: EKCertificate will be set if EK certificate verification + is activated for the agent + properties: + authorityChains: + description: AuthorityChains will be populated with the certificate + chains of subject names of all intermediate and root CA certificates + that were used to verify the EK cert. Every possible path of + verification will populate its own chain which is why this is + a double array type. In reality the outer array is expected + to be of size 1. This will only be set on successful verification, + so only when `verified` is true. + items: + items: + type: string + type: array + type: array + tpm: + description: TPM contains additional information about the EK + and the TPM that is a part of the EK certificate in the "Subject + Alternative Names" and "Subject Directory Attributes" X509v3 + extensions. + properties: + firmwareVersion: + type: string + manufacturer: + type: string + model: + type: string + spec: + properties: + family: + type: string + level: + type: integer + revision: + type: integer + required: + - family + - level + - revision + type: object + type: object + verified: + description: Verified will be true if EK certificate verification + passes successfully. The chains to the CAs will be made available + in the `authorityChains` field. + type: boolean + required: + - verified + type: object + node: + description: Node that the pod of the agent is running on and that + the agent is attesting + type: string + phase: + description: Phase represents the phase that the agent is in from + the view of the controller + type: string + phaseMessage: + description: PhaseMessage is a detailed explanation why the agent + is in that phase. + type: string + phaseReason: + description: PhaseReason is a brief reason why the agent is in that + phase. + type: string + pod: + description: Pod of the agent that is running the agent + type: string + registrar: + description: Registrar reflects the status of the agent in the registrar + properties: + agentCertificate: + description: AgentCert is the DER encoded server certificate of + the agent + format: byte + type: string + agentIP: + description: AgentIP is the IP of where to reach the agent + type: string + agentPort: + description: AgentPort is the port number of where the agent is + listening on + type: integer + aik: + description: 'AIK is base64 encoded. The AIK format is TPM2B_PUBLIC + from tpm2-tss. TODO: break this down' + format: byte + type: string + ek: + description: EK is the public key of the endorsement key + format: byte + type: string + ekCertificate: + description: EKCert is the DER encoded certificate for the endorsment + key + format: byte + type: string + regcount: + description: RegCount is the registration counter + type: integer + type: object + securePayloadDelivered: + description: SecurePayloadDelivered denotes the secure payload that + was delivered to the agent if any at all. + type: string + verifier: + description: 'Verifier reflects the status of the agent in the verifier. + NOTE: this will only be populated if the agent has been added to + a verifier.' + properties: + acceptTPMEncAlgs: + items: + type: string + type: array + acceptTPMHashAlgs: + items: + type: string + type: array + acceptTPMSignAlgs: + items: + type: string + type: array + attestationCount: + type: integer + encAlg: + type: string + hasMBRefState: + type: boolean + hasRuntimePolicy: + type: boolean + hashAlg: + type: string + lastEventID: + type: string + lastReceivedQuote: + format: date-time + type: string + lastSuccessfulAttestation: + format: date-time + type: string + metadata: + type: string + operationalState: + type: string + operationalStateDescription: + type: string + severityLevel: + type: integer + signAlg: + type: string + tpmPolicy: + properties: + "0": + items: + type: string + type: array + "1": + items: + type: string + type: array + "2": + items: + type: string + type: array + "3": + items: + type: string + type: array + "4": + items: + type: string + type: array + "5": + items: + type: string + type: array + "6": + items: + type: string + type: array + "7": + items: + type: string + type: array + "8": + items: + type: string + type: array + "9": + items: + type: string + type: array + "10": + items: + type: string + type: array + "11": + items: + type: string + type: array + "12": + items: + type: string + type: array + "13": + items: + type: string + type: array + "14": + items: + type: string + type: array + "15": + items: + type: string + type: array + "16": + items: + type: string + type: array + "17": + items: + type: string + type: array + "18": + items: + type: string + type: array + "19": + items: + type: string + type: array + "20": + items: + type: string + type: array + "21": + items: + type: string + type: array + "22": + items: + type: string + type: array + "23": + items: + type: string + type: array + mask: + type: string + type: object + v: + format: byte + type: string + vtpmPolicy: + properties: + "0": + items: + type: string + type: array + "1": + items: + type: string + type: array + "2": + items: + type: string + type: array + "3": + items: + type: string + type: array + "4": + items: + type: string + type: array + "5": + items: + type: string + type: array + "6": + items: + type: string + type: array + "7": + items: + type: string + type: array + "8": + items: + type: string + type: array + "9": + items: + type: string + type: array + "10": + items: + type: string + type: array + "11": + items: + type: string + type: array + "12": + items: + type: string + type: array + "13": + items: + type: string + type: array + "14": + items: + type: string + type: array + "15": + items: + type: string + type: array + "16": + items: + type: string + type: array + "17": + items: + type: string + type: array + "18": + items: + type: string + type: array + "19": + items: + type: string + type: array + "20": + items: + type: string + type: array + "21": + items: + type: string + type: array + "22": + items: + type: string + type: array + "23": + items: + type: string + type: array + mask: + type: string + type: object + required: + - hasMBRefState + - hasRuntimePolicy + type: object + verifierName: + description: VerifierName is the verifier that the agent is scheduled + on. This will reflect the same value as the `.spec.verifierName` + once the controller has achieved that state. + type: string + required: + - phase + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: null + storedVersions: null diff --git a/bundle/metadata/annotations.yaml b/bundle/metadata/annotations.yaml new file mode 100644 index 0000000..b41c833 --- /dev/null +++ b/bundle/metadata/annotations.yaml @@ -0,0 +1,15 @@ +annotations: + # Core bundle annotations. + operators.operatorframework.io.bundle.mediatype.v1: registry+v1 + operators.operatorframework.io.bundle.manifests.v1: manifests/ + operators.operatorframework.io.bundle.metadata.v1: metadata/ + operators.operatorframework.io.bundle.package.v1: attestation-operator + operators.operatorframework.io.bundle.channels.v1: alpha + operators.operatorframework.io.bundle.channel.default.v1: stable + operators.operatorframework.io.metrics.builder: operator-sdk-v1.33.0 + operators.operatorframework.io.metrics.mediatype.v1: metrics+v1 + operators.operatorframework.io.metrics.project_layout: go.kubebuilder.io/v4 + + # Annotations for testing. + operators.operatorframework.io.test.mediatype.v1: scorecard+v1 + operators.operatorframework.io.test.config.v1: tests/scorecard/ diff --git a/bundle/tests/scorecard/config.yaml b/bundle/tests/scorecard/config.yaml new file mode 100644 index 0000000..2acb0c8 --- /dev/null +++ b/bundle/tests/scorecard/config.yaml @@ -0,0 +1,70 @@ +apiVersion: scorecard.operatorframework.io/v1alpha3 +kind: Configuration +metadata: + name: config +stages: +- parallel: true + tests: + - entrypoint: + - scorecard-test + - basic-check-spec + image: quay.io/operator-framework/scorecard-test:v1.32.0 + labels: + suite: basic + test: basic-check-spec-test + storage: + spec: + mountPath: {} + - entrypoint: + - scorecard-test + - olm-bundle-validation + image: quay.io/operator-framework/scorecard-test:v1.33.0 + labels: + suite: olm + test: olm-bundle-validation-test + storage: + spec: + mountPath: {} + - entrypoint: + - scorecard-test + - olm-crds-have-validation + image: quay.io/operator-framework/scorecard-test:v1.33.0 + labels: + suite: olm + test: olm-crds-have-validation-test + storage: + spec: + mountPath: {} + - entrypoint: + - scorecard-test + - olm-crds-have-resources + image: quay.io/operator-framework/scorecard-test:v1.33.0 + labels: + suite: olm + test: olm-crds-have-resources-test + storage: + spec: + mountPath: {} + - entrypoint: + - scorecard-test + - olm-spec-descriptors + image: quay.io/operator-framework/scorecard-test:v1.33.0 + labels: + suite: olm + test: olm-spec-descriptors-test + storage: + spec: + mountPath: {} + - entrypoint: + - scorecard-test + - olm-status-descriptors + image: quay.io/operator-framework/scorecard-test:v1.33.0 + labels: + suite: olm + test: olm-status-descriptors-test + storage: + spec: + mountPath: {} +storage: + spec: + mountPath: {} diff --git a/config/manifests/attestation-operator.clusterserviceversion.yaml b/config/manifests/attestation-operator.clusterserviceversion.yaml new file mode 100644 index 0000000..c7fd96d --- /dev/null +++ b/config/manifests/attestation-operator.clusterserviceversion.yaml @@ -0,0 +1,251 @@ +apiVersion: operators.coreos.com/v1alpha1 +kind: ClusterServiceVersion +metadata: + annotations: + alm-examples: |- + [ + { + "apiVersion": "attestation.keylime.dev/v1alpha1", + "kind": "Agent", + "metadata": { + "labels": { + "app.kubernetes.io/created-by": "attestation-operator", + "app.kubernetes.io/instance": "agent-sample", + "app.kubernetes.io/managed-by": "kustomize", + "app.kubernetes.io/name": "agent", + "app.kubernetes.io/part-of": "attestation-operator" + }, + "name": "agent-sample" + }, + "spec": null + } + ] + capabilities: Basic Install + createdAt: "2024-01-24T11:51:41Z" + operators.operatorframework.io/builder: operator-sdk-v1.32.0 + operators.operatorframework.io/project_layout: go.kubebuilder.io/v4 + name: attestation-operator.v0.1.0 + namespace: placeholder +spec: + apiservicedefinitions: {} + customresourcedefinitions: + owned: + - kind: Agent + name: agents.attestation.keylime.dev + version: v1alpha1 + description: Operator SDK based Attestation Operator + displayName: osdk-attestation-operator + icon: + - base64data: "" + mediatype: "" + install: + spec: + clusterPermissions: + - rules: + - apiGroups: + - attestation.keylime.dev + resources: + - agents + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: + - attestation.keylime.dev + resources: + - agents/finalizers + verbs: + - update + - apiGroups: + - attestation.keylime.dev + resources: + - agents/status + verbs: + - get + - patch + - update + - apiGroups: + - "" + resources: + - pods + verbs: + - get + - list + - watch + - apiGroups: + - "" + resources: + - secrets + verbs: + - get + - list + - watch + - apiGroups: + - authentication.k8s.io + resources: + - tokenreviews + verbs: + - create + - apiGroups: + - authorization.k8s.io + resources: + - subjectaccessreviews + verbs: + - create + serviceAccountName: attestation-operator-controller-manager + deployments: + - label: + app.kubernetes.io/component: manager + app.kubernetes.io/created-by: attestation-operator + app.kubernetes.io/instance: controller-manager + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: deployment + app.kubernetes.io/part-of: attestation-operator + control-plane: controller-manager + name: attestation-operator-controller-manager + spec: + replicas: 1 + selector: + matchLabels: + control-plane: controller-manager + strategy: {} + template: + metadata: + annotations: + kubectl.kubernetes.io/default-container: manager + labels: + control-plane: controller-manager + spec: + containers: + - args: + - --leader-elect + command: + - /bin/attestation-operator + env: + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: KEYLIME_REGISTRAR_URL + value: https://10.110.133.5:8891/ + - name: KEYLIME_VERIFIER_URL + value: https://10.110.231.226:8881/ + - name: KEYLIME_CLIENT_KEY + value: /var/lib/keylime/cv_ca/client-private.pem + - name: KEYLIME_CLIENT_CERT + value: /var/lib/keylime/cv_ca/client-cert.crt + - name: KEYLIME_REGISTRAR_SYNCHRONIZER_INTERVAL_DURATION + value: 10s + - name: KEYLIME_AGENT_RECONCILE_INTERVAL_DURATION + value: 5s + - name: KEYLIME_TPM_CERT_STORE + value: /var/lib/keylime/tpm_cert_store + - name: KEYLIME_SECURE_PAYLOAD_DIR + value: /var/lib/keylime/secure_payload + image: quay.io/sec-eng-special/attestation_operator:v0.1.0 + livenessProbe: + httpGet: + path: /healthz + port: 8081 + initialDelaySeconds: 15 + periodSeconds: 20 + name: manager + readinessProbe: + httpGet: + path: /readyz + port: 8081 + initialDelaySeconds: 5 + periodSeconds: 10 + resources: + limits: + cpu: 500m + memory: 128Mi + requests: + cpu: 10m + memory: 64Mi + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + volumeMounts: + - mountPath: /var/lib/keylime/cv_ca/ + name: certs + readOnly: true + - mountPath: /var/lib/keylime/tpm_cert_store + name: tpm-cert-store + readOnly: true + securityContext: + runAsNonRoot: true + serviceAccountName: attestation-operator-controller-manager + terminationGracePeriodSeconds: 10 + volumes: + - name: certs + secret: + defaultMode: 420 + secretName: hhkl-keylime-certs + - name: tpm-cert-store + secret: + defaultMode: 420 + secretName: keylime-swtpm-cert-store + permissions: + - 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 + serviceAccountName: attestation-operator-controller-manager + strategy: deployment + installModes: + - supported: false + type: OwnNamespace + - supported: false + type: SingleNamespace + - supported: false + type: MultiNamespace + - supported: true + type: AllNamespaces + keywords: + - attestation + - security + links: + - name: Osdk Attestation Operator + url: https://osdk-attestation-operator.domain + maintainers: + - email: sarroutb@redhat.com + name: Sergio Arroutbi + maturity: alpha + provider: + name: Red Hat Inc + version: 0.1.0 diff --git a/config/manifests/bases/attestation-operator.clusterserviceversion.yaml b/config/manifests/bases/attestation-operator.clusterserviceversion.yaml new file mode 100644 index 0000000..87c1dff --- /dev/null +++ b/config/manifests/bases/attestation-operator.clusterserviceversion.yaml @@ -0,0 +1,81 @@ +apiVersion: operators.coreos.com/v1alpha1 +kind: ClusterServiceVersion +metadata: + annotations: + alm-examples: '[]' + capabilities: Basic Install + name: attestation-operator.v0.0.0 + namespace: placeholder +spec: + apiservicedefinitions: {} + customresourcedefinitions: + owned: + - description: Attestation is the Schema for the attestations API + displayName: Attestation + kind: Attestation + name: attestations.keylime.dev + specDescriptors: + - description: PodRetrievalInfo allows specifying information required to retrieve + a list of pods + displayName: Information for pod list retrieval + path: podretrieval + - description: Enabled allows specifying if want to retrieve the list of pods + displayName: Set to True to list pods + path: podretrieval.enabled + - description: Namespace allows specifying namespace where to retrieve the list + of pods + displayName: Indicate namespace for pod retrieval + path: podretrieval.namespace + statusDescriptors: + - description: PodList stores the list of pods retrieved + displayName: List of Pods + path: podlist + x-descriptors: + - urn:alm:descriptor:text + - description: PodName represents the name of the pod + displayName: Pod Name + path: podlist[0].name + x-descriptors: + - urn:alm:descriptor:text + - description: Status contains the status of the pod + displayName: Pod Status + path: podlist[0].status + x-descriptors: + - urn:alm:descriptor:text + - description: Version contains the version of the attestation operator + displayName: Version + path: version + x-descriptors: + - urn:alm:descriptor:text + version: v1alpha1 + description: Operator SDK based Attestation Operator + displayName: osdk-attestation-operator + icon: + - base64data: "" + mediatype: "" + install: + spec: + deployments: null + strategy: "" + installModes: + - supported: false + type: OwnNamespace + - supported: false + type: SingleNamespace + - supported: false + type: MultiNamespace + - supported: true + type: AllNamespaces + keywords: + - attestation + - security + links: + - name: Osdk Attestation Operator + url: https://osdk-attestation-operator.domain + maintainers: + - email: sarroutb@redhat.com + name: Sergio Arroutbi + maturity: alpha + provider: + name: Red Hat Inc + version: 0.0.0 diff --git a/config/manifests/kustomization.yaml b/config/manifests/kustomization.yaml new file mode 100644 index 0000000..eaa5e2a --- /dev/null +++ b/config/manifests/kustomization.yaml @@ -0,0 +1,27 @@ +# These resources constitute the fully configured set of manifests +# used to generate the 'manifests/' directory in a bundle. +resources: +- bases/attestation-operator.clusterserviceversion.yaml +- ../default +- ../samples +- ../scorecard + +# [WEBHOOK] To enable webhooks, uncomment all the sections with [WEBHOOK] prefix. +# Do NOT uncomment sections with prefix [CERTMANAGER], as OLM does not support cert-manager. +# These patches remove the unnecessary "cert" volume and its manager container volumeMount. +#patchesJson6902: +#- target: +# group: apps +# version: v1 +# kind: Deployment +# name: controller-manager +# namespace: system +# patch: |- +# # Remove the manager container's "cert" volumeMount, since OLM will create and mount a set of certs. +# # Update the indices in this path if adding or removing containers/volumeMounts in the manager's Deployment. +# - op: remove +# path: /spec/template/spec/containers/1/volumeMounts/0 +# # Remove the "cert" volume, since OLM will create and mount a set of certs. +# # Update the indices in this path if adding or removing volumes in the manager's Deployment. +# - op: remove +# path: /spec/template/spec/volumes/0 diff --git a/config/scorecard/bases/config.yaml b/config/scorecard/bases/config.yaml new file mode 100644 index 0000000..c770478 --- /dev/null +++ b/config/scorecard/bases/config.yaml @@ -0,0 +1,7 @@ +apiVersion: scorecard.operatorframework.io/v1alpha3 +kind: Configuration +metadata: + name: config +stages: +- parallel: true + tests: [] diff --git a/config/scorecard/kustomization.yaml b/config/scorecard/kustomization.yaml new file mode 100644 index 0000000..50cd2d0 --- /dev/null +++ b/config/scorecard/kustomization.yaml @@ -0,0 +1,16 @@ +resources: +- bases/config.yaml +patchesJson6902: +- path: patches/basic.config.yaml + target: + group: scorecard.operatorframework.io + version: v1alpha3 + kind: Configuration + name: config +- path: patches/olm.config.yaml + target: + group: scorecard.operatorframework.io + version: v1alpha3 + kind: Configuration + name: config +#+kubebuilder:scaffold:patchesJson6902 diff --git a/config/scorecard/patches/basic.config.yaml b/config/scorecard/patches/basic.config.yaml new file mode 100644 index 0000000..472a988 --- /dev/null +++ b/config/scorecard/patches/basic.config.yaml @@ -0,0 +1,10 @@ +- op: add + path: /stages/0/tests/- + value: + entrypoint: + - scorecard-test + - basic-check-spec + image: quay.io/operator-framework/scorecard-test:v1.32.0 + labels: + suite: basic + test: basic-check-spec-test diff --git a/config/scorecard/patches/olm.config.yaml b/config/scorecard/patches/olm.config.yaml new file mode 100644 index 0000000..9b7ca41 --- /dev/null +++ b/config/scorecard/patches/olm.config.yaml @@ -0,0 +1,50 @@ +- op: add + path: /stages/0/tests/- + value: + entrypoint: + - scorecard-test + - olm-bundle-validation + image: quay.io/operator-framework/scorecard-test:v1.33.0 + labels: + suite: olm + test: olm-bundle-validation-test +- op: add + path: /stages/0/tests/- + value: + entrypoint: + - scorecard-test + - olm-crds-have-validation + image: quay.io/operator-framework/scorecard-test:v1.33.0 + labels: + suite: olm + test: olm-crds-have-validation-test +- op: add + path: /stages/0/tests/- + value: + entrypoint: + - scorecard-test + - olm-crds-have-resources + image: quay.io/operator-framework/scorecard-test:v1.33.0 + labels: + suite: olm + test: olm-crds-have-resources-test +- op: add + path: /stages/0/tests/- + value: + entrypoint: + - scorecard-test + - olm-spec-descriptors + image: quay.io/operator-framework/scorecard-test:v1.33.0 + labels: + suite: olm + test: olm-spec-descriptors-test +- op: add + path: /stages/0/tests/- + value: + entrypoint: + - scorecard-test + - olm-status-descriptors + image: quay.io/operator-framework/scorecard-test:v1.33.0 + labels: + suite: olm + test: olm-status-descriptors-test