diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..4e0abbc --- /dev/null +++ b/.gitattributes @@ -0,0 +1,6 @@ +# The .t files are cram tests. The GitHub syntax highlighter [1] does not know +# about the cram format and thinks they are Perl files. So we disabled the +# GitHub highlighter altogether for these files. + +*.t text linguist-language=Text + diff --git a/.gitignore b/.gitignore index 2ebd490..f912bf2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ ca.crt ca.key +*.t.err diff --git a/chart/jetstack-secure-gcm/charts/google-cas-issuer/templates/crds.yaml b/chart/jetstack-secure-gcm/charts/google-cas-issuer/templates/crds.yaml index 8c1a25f..c911f06 100644 --- a/chart/jetstack-secure-gcm/charts/google-cas-issuer/templates/crds.yaml +++ b/chart/jetstack-secure-gcm/charts/google-cas-issuer/templates/crds.yaml @@ -1,12 +1,13 @@ {{- if .Values.installCRDs }} -apiVersion: apiextensions.k8s.io/v1beta1 +apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.2.2 - name: googlecasclusterissuers.cas-issuer.jetstack.io labels: {{- include "google-cas-issuer.labels" . | nindent 4 }} + annotations: + controller-gen.kubebuilder.io/version: v0.5.0 + creationTimestamp: null + name: googlecasclusterissuers.cas-issuer.jetstack.io spec: group: cas-issuer.jetstack.io names: @@ -15,106 +16,103 @@ spec: plural: googlecasclusterissuers singular: googlecasclusterissuer scope: Cluster - subresources: - status: {} - validation: - openAPIV3Schema: - description: GoogleCASClusterIssuer is the Schema for the googlecasclusterissuers - 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: GoogleCASIssuerSpec defines the desired state of GoogleCASIssuer - properties: - certificateAuthorityID: - description: CertificateAuthorityID is The ID of the Google Private - certificate authority that will sign certificates - type: string - credentials: - description: Credentials is a reference to a Kubernetes Secret Key that - contains Google Service Account Credentials - properties: - key: - description: The key of the entry in the Secret resource's `data` - field to be used. Some instances of this field may be defaulted, - in others it may be required. - type: string - name: - description: "Name of the resource being referred to. More info: - https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names" - type: string - required: - - name - type: object - location: - description: Location is the Google Cloud Project Location - type: string - project: - description: Project is the Google Cloud Project ID - type: string - type: object - status: - description: GoogleCASIssuerStatus defines the observed state of GoogleCASIssuer - properties: - conditions: - items: - description: IssuerCondition contains condition information for a - CAS Issuer. + versions: + - additionalPrinterColumns: + - jsonPath: .status.conditions[?(@.type=='Ready')].status + name: ready + type: string + - jsonPath: .status.conditions[?(@.type=='Ready')].reason + name: reason + type: string + - jsonPath: .status.conditions[?(@.type=='Ready')].message + name: message + type: string + name: v1beta1 + schema: + openAPIV3Schema: + description: GoogleCASClusterIssuer is the Schema for the googlecasclusterissuers 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: GoogleCASIssuerSpec defines the desired state of GoogleCASIssuer + properties: + caPoolId: + description: CaPoolId is the id of the CA pool to issue certificates from + type: string + certificateAuthorityId: + description: CertificateAuthorityId is specific certificate authority to use to sign. Omit in order to load balance across all CAs in the pool + type: string + credentials: + description: Credentials is a reference to a Kubernetes Secret Key that contains Google Service Account Credentials properties: - lastTransitionTime: - description: LastTransitionTime is the timestamp corresponding - to the last status change of this condition. - format: date-time - type: string - message: - description: Message is a human readable description of the details - of the last transition, complementing reason. + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. type: string - reason: - description: Reason is a brief machine readable explanation for - the condition's last transition. + name: + description: 'Name of the resource being referred to. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' type: string - status: - allOf: + required: + - name + type: object + location: + description: Location is the Google Cloud Project Location + type: string + project: + description: Project is the Google Cloud Project ID + type: string + type: object + status: + description: GoogleCASIssuerStatus defines the observed state of GoogleCASIssuer + properties: + conditions: + items: + description: IssuerCondition contains condition information for a CAS Issuer. + properties: + lastTransitionTime: + description: LastTransitionTime is the timestamp corresponding to the last status change of this condition. + format: date-time + type: string + message: + description: Message is a human readable description of the details of the last transition, complementing reason. + type: string + reason: + description: Reason is a brief machine readable explanation for the condition's last transition. + type: string + status: + allOf: - enum: - - "True" - - "False" - - Unknown + - "True" + - "False" + - Unknown - enum: - - "True" - - "False" - - Unknown - description: Status of the condition, one of ('True', 'False', - 'Unknown'). - type: string - type: - description: Type of the condition, currently ('Ready'). - enum: + - "True" + - "False" + - Unknown + description: Status of the condition, one of ('True', 'False', 'Unknown'). + type: string + type: + description: Type of the condition, currently ('Ready'). + enum: - Ready - type: string - required: + type: string + required: - status - type - type: object - type: array - type: object - type: object - version: v1alpha1 - versions: - - name: v1alpha1 - served: true - storage: true + type: object + type: array + type: object + type: object + served: true + storage: true + subresources: + status: {} status: acceptedNames: kind: "" @@ -122,14 +120,13 @@ status: conditions: [] storedVersions: [] --- -apiVersion: apiextensions.k8s.io/v1beta1 +apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.2.2 + controller-gen.kubebuilder.io/version: v0.5.0 + creationTimestamp: null name: googlecasissuers.cas-issuer.jetstack.io - labels: - {{- include "google-cas-issuer.labels" . | nindent 4 }} spec: group: cas-issuer.jetstack.io names: @@ -137,110 +134,108 @@ spec: listKind: GoogleCASIssuerList plural: googlecasissuers singular: googlecasissuer - scope: "" - subresources: - status: {} - validation: - openAPIV3Schema: - description: GoogleCASIssuer is the Schema for the googlecasissuers 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: GoogleCASIssuerSpec defines the desired state of GoogleCASIssuer - properties: - certificateAuthorityID: - description: CertificateAuthorityID is The ID of the Google Private - certificate authority that will sign certificates - type: string - credentials: - description: Credentials is a reference to a Kubernetes Secret Key that - contains Google Service Account Credentials - properties: - key: - description: The key of the entry in the Secret resource's `data` - field to be used. Some instances of this field may be defaulted, - in others it may be required. - type: string - name: - description: "Name of the resource being referred to. More info: - https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names" - type: string - required: - - name - type: object - location: - description: Location is the Google Cloud Project Location - type: string - project: - description: Project is the Google Cloud Project ID - type: string - type: object - status: - description: GoogleCASIssuerStatus defines the observed state of GoogleCASIssuer - properties: - conditions: - items: - description: IssuerCondition contains condition information for a - CAS Issuer. + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .status.conditions[?(@.type=='Ready')].status + name: ready + type: string + - jsonPath: .status.conditions[?(@.type=='Ready')].reason + name: reason + type: string + - jsonPath: .status.conditions[?(@.type=='Ready')].message + name: message + type: string + name: v1beta1 + schema: + openAPIV3Schema: + description: GoogleCASIssuer is the Schema for the googlecasissuers 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: GoogleCASIssuerSpec defines the desired state of GoogleCASIssuer + properties: + caPoolId: + description: CaPoolId is the id of the CA pool to issue certificates from + type: string + certificateAuthorityId: + description: CertificateAuthorityId is specific certificate authority to use to sign. Omit in order to load balance across all CAs in the pool + type: string + credentials: + description: Credentials is a reference to a Kubernetes Secret Key that contains Google Service Account Credentials properties: - lastTransitionTime: - description: LastTransitionTime is the timestamp corresponding - to the last status change of this condition. - format: date-time - type: string - message: - description: Message is a human readable description of the details - of the last transition, complementing reason. + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. type: string - reason: - description: Reason is a brief machine readable explanation for - the condition's last transition. + name: + description: 'Name of the resource being referred to. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' type: string - status: - allOf: + required: + - name + type: object + location: + description: Location is the Google Cloud Project Location + type: string + project: + description: Project is the Google Cloud Project ID + type: string + type: object + status: + description: GoogleCASIssuerStatus defines the observed state of GoogleCASIssuer + properties: + conditions: + items: + description: IssuerCondition contains condition information for a CAS Issuer. + properties: + lastTransitionTime: + description: LastTransitionTime is the timestamp corresponding to the last status change of this condition. + format: date-time + type: string + message: + description: Message is a human readable description of the details of the last transition, complementing reason. + type: string + reason: + description: Reason is a brief machine readable explanation for the condition's last transition. + type: string + status: + allOf: - enum: - - "True" - - "False" - - Unknown + - "True" + - "False" + - Unknown - enum: - - "True" - - "False" - - Unknown - description: Status of the condition, one of ('True', 'False', - 'Unknown'). - type: string - type: - description: Type of the condition, currently ('Ready'). - enum: + - "True" + - "False" + - Unknown + description: Status of the condition, one of ('True', 'False', 'Unknown'). + type: string + type: + description: Type of the condition, currently ('Ready'). + enum: - Ready - type: string - required: + type: string + required: - status - type - type: object - type: array - type: object - type: object - version: v1alpha1 - versions: - - name: v1alpha1 - served: true - storage: true + type: object + type: array + type: object + type: object + served: true + storage: true + subresources: + status: {} status: acceptedNames: kind: "" plural: "" conditions: [] storedVersions: [] -{{- end }} +{{- end }} \ No newline at end of file diff --git a/chart/jetstack-secure-gcm/templates/application.yaml b/chart/jetstack-secure-gcm/templates/application.yaml index 34fedac..d6e00ce 100644 --- a/chart/jetstack-secure-gcm/templates/application.yaml +++ b/chart/jetstack-secure-gcm/templates/application.yaml @@ -44,7 +44,6 @@ spec: url: https://cert-manager.io/docs/usage/ - description: Getting Started with the Jetstack Secure Platform url: https://platform.jetstack.io/docs - info: [] notes: |- ### Create your first certificate diff --git a/cloudbuild.yaml b/cloudbuild.yaml index 1261736..f66e78c 100644 --- a/cloudbuild.yaml +++ b/cloudbuild.yaml @@ -144,7 +144,7 @@ steps: name: gcr.io/cloud-builders/gcloud entrypoint: bash args: - - -exc + - -euc - | while : ; do kubectl get ns -oname 2>/dev/null | grep apptest- && break @@ -158,6 +158,7 @@ steps: done pod=$(kubectl -n "$ns" get pods -oname | grep "apptest-.*-deployer" | cut -d/ -f2) + set -x kubectl wait -n "$ns" --for=condition=ready --timeout=5m pod $pod kubectl logs -n "$ns" $pod -f --tail=-1 waitFor: @@ -168,7 +169,7 @@ steps: name: gcr.io/cloud-builders/gcloud entrypoint: bash args: - - -exc + - -euc - | while : ; do kubectl get ns -oname 2>/dev/null | grep apptest- && break @@ -181,6 +182,7 @@ steps: sleep 10 done + set -x kubectl wait -n "$ns" --for=condition=ready --timeout=5m pod smoke-test-pod kubectl logs -n "$ns" smoke-test-pod -f --tail=-1 waitFor: diff --git a/docs/TESTING-DEPLOYER.md b/docs/TESTING-DEPLOYER.md index 1b264a3..144c9ac 100644 --- a/docs/TESTING-DEPLOYER.md +++ b/docs/TESTING-DEPLOYER.md @@ -10,10 +10,10 @@ **Contents:** +- [Cutting a new release](#cutting-a-new-release) - [Pricing mechanism](#pricing-mechanism) - [Creating and testing the deployer image](#creating-and-testing-the-deployer-image) - [mpdev install on your own cluster](#mpdev-install-on-your-own-cluster) -- [Cutting a new release](#cutting-a-new-release) - [Testing the application without having access to the Billing API](#testing-the-application-without-having-access-to-the-billing-api) - [How the Application object "wrangles" its components](#how-the-application-object-wrangles-its-components) - [Installing and manually testing the deployer image](#installing-and-manually-testing-the-deployer-image) @@ -21,6 +21,40 @@ - [Debugging deployer and smoke-tests when run in Cloud Build](#debugging-deployer-and-smoke-tests-when-run-in-cloud-build) - [Updating the upstream cert-manager chart version](#updating-the-upstream-cert-manager-chart-version) +## Cutting a new release + +Since the process is manual and evolves from release to release, we document all +the steps that were taken in each release directly on the GitHub Release itself +in a `
` block that looks like this: + +> ▶ 📦 Recording of the manual steps of the release process + +Imagining that you want to release `1.1.0-gcm.5`, the steps are: + +1. Copy the `
` block from the previous release [1.1.0-gcm.4](https://github.com/jetstack/jetstack-secure-gcm/releases/tag/1.1.0-gcm.4) +2. In an editor, change the references to `1.1.0-gcm.4`. +3. Follow the steps and tick the checkboxes. +4. After the `1.1.0-gcm.5` is pushed to GitHub, create a GitHub Release for that + tag and paste the content into the `
` block into the GitHub Release + you just created (see `PASTE HERE` below). The GitHub Release description + should look like this: + + ```md + ## Changelog + + + + ## Notes + +
+ + 📦 Recording of the manual steps of the release process + + + +
+ ``` + ## Pricing mechanism Each cluster is priced at $50 a month, billed hourly ($0.07/hour). The way the @@ -32,10 +66,10 @@ of `1` to the `time` value. The unit for `time` is something we have configured in the [pricing panel](https://console.cloud.google.com/partner/editor/jetstack-public/jetstack-secure-for-cert-manager?project=jetstack-public&authuser=4&form=saasK8sPricingPanel). -| Field | Value | -| -------------- | ------ | -| ID | `time` | -| Unit | `h` | +| Field | Value | +| ----- | ------ | +| ID | `time` | +| Unit | `h` | Note that the cert-manager deployment should always be run with replicas=1. High-availability (replicas > 1) is not supported yet, and the application will @@ -298,22 +332,6 @@ see everything green: The application page for test-1 shows that all the deployments are green. This screenshot is stored in this issue: https://github.com/jetstack/jetstack-secure-gcm/issues/21 -## Cutting a new release - -Since the process is manual and evolves from release to release, we document all -the steps taken in each release directly on the GitHub Release itself in a -`
` block that looks like this: - -> ▶ 📦 Recording of the manual steps of the release process - -For example, when releasing `1.1.0-gcm.5`, the steps were: - -1. Copy the `
` block from the previous release [1.1.0-gcm.4](https://github.com/jetstack/jetstack-secure-gcm/releases/tag/1.1.0-gcm.4) -2. In an editor, change the references to `1.1.0-gcm.4`. -3. Follow the steps and tick the checkboxes. -4. After the `1.1.0-gcm.5` is pushed to GitHub, create a GitHub Release for that - tag and paste the content the `
` block to the GitHub Release. - ## Testing the application without having access to the Billing API Jetstack members do not have access to the Billing API. In order to test @@ -552,7 +570,7 @@ the example [suite.yaml](https://github.com/GoogleCloudPlatform/marketplace-test ```yaml actions: - - name: { { .Env.TEST_NAME } } + - name: "{{ .Env.TEST_NAME }}" httpTest: url: http://{{ .Var.MainVmIp }}:9012 expect: diff --git a/schema.yaml b/schema.yaml index 9e17038..5281853 100644 --- a/schema.yaml +++ b/schema.yaml @@ -14,7 +14,7 @@ x-google-marketplace: # # Important: it must have the same value as the version in the # Application manifest. - publishedVersion: 1.3.1-gcm.0 + publishedVersion: 1.4.0-gcm.0 publishedVersionMetadata: releaseNote: >- Initial release. @@ -107,6 +107,12 @@ properties: serviceAccount: description: Service account used by cert-manager Controller Deployment roles: + - type: Role + rulesType: CUSTOM + rules: + - apiGroups: [""] + resources: ["events"] + verbs: ["create", "patch"] - type: ClusterRole rulesType: CUSTOM rules: @@ -120,9 +126,6 @@ properties: - apiGroups: [""] resources: ["secrets"] verbs: ["get", "list", "watch", "create", "update", "delete"] - - apiGroups: [""] - resources: ["events"] - verbs: ["create", "patch"] # ClusterIssuer controller role - apiGroups: ["cert-manager.io"] resources: ["clusterissuers", "clusterissuers/status"] @@ -133,9 +136,6 @@ properties: - apiGroups: [""] resources: ["secrets"] verbs: ["get", "list", "watch", "create", "update", "delete"] - - apiGroups: [""] - resources: ["events"] - verbs: ["create", "patch"] # Certificates controller role - apiGroups: ["cert-manager.io"] resources: ["certificates", "certificates/status", "certificaterequests", "certificaterequests/status"] @@ -152,9 +152,6 @@ properties: - apiGroups: [""] resources: ["secrets"] verbs: ["get", "list", "watch", "create", "update", "delete"] - - apiGroups: [""] - resources: ["events"] - verbs: ["create", "patch"] # Orders controller role - apiGroups: ["acme.cert-manager.io"] resources: ["orders", "orders/status"] @@ -174,9 +171,6 @@ properties: - apiGroups: [""] resources: ["secrets"] verbs: ["get", "list", "watch"] - - apiGroups: [""] - resources: ["events"] - verbs: ["create", "patch"] # Challenges controller role - apiGroups: ["acme.cert-manager.io"] resources: ["challenges", "challenges/status"] @@ -190,9 +184,6 @@ properties: - apiGroups: [""] resources: ["secrets"] verbs: ["get", "list", "watch"] - - apiGroups: [""] - resources: ["events"] - verbs: ["create", "patch"] - apiGroups: [""] resources: ["pods", "services"] verbs: ["get", "list", "watch", "create", "delete"] @@ -226,12 +217,7 @@ properties: - apiGroups: ["networking.k8s.io"] resources: ["ingresses"] verbs: ["get", "list", "watch"] - - apiGroups: [""] - resources: ["events"] - verbs: ["create", "patch"] - - apiGroups: [""] - resources: ["configmaps"] - verbs: ["get", "create", "update", "patch"] + - apiGroups: ["cert-manager.io"] resources: ["signers"] verbs: ["approve"] @@ -242,6 +228,43 @@ properties: - googlecasclusterissuers.cas-issuer.jetstack.io/* - googlecasissuers.cas-issuer.jetstack.io/* + # Added in https://github.com/jetstack/cert-manager/pull/4064 + - apiGroups: ["certificates.k8s.io"] + resources: ["certificatesigningrequests"] + verbs: ["get", "list", "watch", "update"] + - apiGroups: ["certificates.k8s.io"] + resources: ["certificatesigningrequests/status"] + verbs: ["update"] + - apiGroups: ["certificates.k8s.io"] + resources: ["signers"] + resourceNames: ["issuers.cert-manager.io/*", "clusterissuers.cert-manager.io/*"] + verbs: ["sign"] + - apiGroups: ["authorization.k8s.io"] + resources: ["subjectaccessreviews"] + verbs: ["create"] + + # Leader election roles. Although leader election only operates on + # one single namespace (often kube-system), we have to use a + # ClusterRole due to schema.yaml limitations: + # https://github.com/GoogleCloudPlatform/marketplace-k8s-app-tools/issues/564 + - apiGroups: [""] + verbs: [create] + resources: [configmaps] + - apiGroups: [""] + resources: [configmaps] + verbs: [get, list, watch, update, patch, delete] + resourceNames: ["cert-manager-controller"] + - apiGroups: [""] + resources: [configmaps/status] + verbs: [get, update, patch] + - apiGroups: [coordination.k8s.io] + resources: [leases] + verbs: [create] + - apiGroups: [coordination.k8s.io] + resources: [leases] + verbs: [get, update, patch] + resourceNames: ["cert-manager-controller"] + cert-manager.webhook.serviceAccount.name: type: string title: Name of the Kubernetes service account for the cert-manager webhook @@ -274,19 +297,10 @@ properties: - type: Role rulesType: CUSTOM rules: - # Leader election roles. - - apiGroups: [""] - resources: [configmaps] - verbs: [get, list, watch, create, update, patch, delete] - - apiGroups: [""] - resources: [configmaps/status] - verbs: [get, update, patch] - apiGroups: [""] resources: [events] verbs: [create] - - apiGroups: [coordination.k8s.io] - resources: [leases] - verbs: [create, get, list, update] + - type: ClusterRole rulesType: CUSTOM rules: @@ -312,30 +326,36 @@ properties: resources: ["configmaps"] verbs: ["get", "create", "update", "patch"] - google-cas-issuer.serviceAccount.name: - type: string - title: Name of the Kubernetes service account for the google-cas-issuer - x-google-marketplace: - type: SERVICE_ACCOUNT - serviceAccount: - description: Service account used by google-cas-issuer - roles: - - type: Role - rulesType: CUSTOM - rules: - # Leader election roles. + # Leader election roles. Although leader election only operates on + # one single namespace (often kube-system), we have to use a + # ClusterRole due to schema.yaml limitations: + # https://github.com/GoogleCloudPlatform/marketplace-k8s-app-tools/issues/564 + - apiGroups: [""] + verbs: [create] + resources: [configmaps] - apiGroups: [""] resources: [configmaps] - verbs: [get, list, watch, create, update, patch, delete] + verbs: [get, list, watch, update, patch, delete] + resourceNames: ["cert-manager-cainjector-leader-election", "cert-manager-cainjector-leader-election-core"] - apiGroups: [""] resources: [configmaps/status] verbs: [get, update, patch] - - apiGroups: [""] - resources: [events] + - apiGroups: [coordination.k8s.io] + resources: [leases] verbs: [create] - apiGroups: [coordination.k8s.io] resources: [leases] - verbs: [create, get, list, update] + verbs: [get, update, patch] + resourceNames: ["cert-manager-cainjector-leader-election", "cert-manager-cainjector-leader-election-core"] + + google-cas-issuer.serviceAccount.name: + type: string + title: Name of the Kubernetes service account for the google-cas-issuer + x-google-marketplace: + type: SERVICE_ACCOUNT + serviceAccount: + description: Service account used by google-cas-issuer + roles: - type: ClusterRole rulesType: CUSTOM rules: @@ -364,6 +384,28 @@ properties: resources: [certificaterequests/status] verbs: [get, patch, update] + # Leader election roles. Although leader election only operates on + # one single namespace (often kube-system), we have to use a + # ClusterRole due to schema.yaml limitations: + # https://github.com/GoogleCloudPlatform/marketplace-k8s-app-tools/issues/564 + - apiGroups: [""] + verbs: [create] + resources: [configmaps] + - apiGroups: [""] + resources: [configmaps] + verbs: [get, list, watch, update, patch, delete] + resourceNames: ["cm-google-cas-issuer"] + - apiGroups: [""] + resources: [configmaps/status] + verbs: [get, update, patch] + - apiGroups: [coordination.k8s.io] + resources: [leases] + verbs: [create] + - apiGroups: [coordination.k8s.io] + resources: [leases] + verbs: [get, update, patch] + resourceNames: ["cm-google-cas-issuer"] + preflight.serviceAccount.name: type: string title: Name of the Kubernetes service account for the Jetstack Secure agent diff --git a/smoke-test.Dockerfile b/smoke-test.Dockerfile index 9b8e3fe..7467263 100644 --- a/smoke-test.Dockerfile +++ b/smoke-test.Dockerfile @@ -7,19 +7,18 @@ # certificate using the Google CAS issuer?" # Dockerfile: https://github.com/GoogleCloudPlatform/marketplace-testrunner/blob/master/Dockerfile -FROM gcr.io/cloud-marketplace-tools/testrunner:0.1.2 +FROM python:alpine -RUN apt-get update && apt-get install -y --no-install-recommends \ - curl wget dnsutils netcat jq \ - && rm -rf /var/lib/apt/lists/* +RUN apk add curl patch +RUN pip3 install cram +RUN curl -L https://github.com/stern/stern/releases/download/v1.19.0/stern_1.19.0_linux_amd64.tar.gz | tar xz -C /tmp \ + && mv /tmp/stern_1.19.0_linux_amd64/stern /usr/local/bin \ + && curl -L https://storage.googleapis.com/kubernetes-release/release/v1.19.6/bin/linux/amd64/kubectl --output-dir /usr/local/bin -O \ + && chmod 755 /usr/local/bin/kubectl -RUN mkdir -p /opt/kubectl/1.19 \ - && wget -q -O /opt/kubectl/1.19/kubectl \ - https://storage.googleapis.com/kubernetes-release/release/v1.19.6/bin/linux/amd64/kubectl \ - && chmod 755 /opt/kubectl/1.19/kubectl \ - && ln -s /opt/kubectl/1.19/kubectl /usr/bin/kubectl +WORKDIR /opt +COPY smoke-test.t . -COPY smoke-test.yaml /smoke-test.yaml +ENV NAMESPACE=test -WORKDIR / -ENTRYPOINT ["testrunner", "-logtostderr", "--test_spec=/smoke-test.yaml"] +CMD ["sh", "-c", "cram smoke-test.t || (stern -A -l app.kubernetes.io/name=jetstack-secure-gcm; exit 1)"] diff --git a/smoke-test.t b/smoke-test.t new file mode 100644 index 0000000..723313f --- /dev/null +++ b/smoke-test.t @@ -0,0 +1,105 @@ +This file is written using the "cram" format. We could have used a simple Bash +script, but cram tests make it very easy to spot when something "changes" e.g. +stderr or stdout mismatch. + +This file is used in the smoke-test image (smoke-test.Dockerfile) to run the +test suite. This image is used in a Job in data-test. mpdev verify detects the +presence of this Job thanks to the annotation + "marketplace.cloud.google.com/verification: test" + +First, let us create a self-signed Issuer and a Certificate. This is a good way +to spot webhook misconfigurations. + + $ kubectl apply -n ${NAMESPACE} -f - < apiVersion: cert-manager.io/v1 + > kind: Issuer + > metadata: + > name: selfsigned-issuer + > spec: + > selfSigned: {} + > --- + > apiVersion: cert-manager.io/v1 + > kind: Certificate + > metadata: + > name: selfsigned-cert + > spec: + > dnsNames: + > - example.com + > secretName: selfsigned-cert-tls + > issuerRef: + > name: selfsigned-issuer + > EOF + issuer.cert-manager.io/selfsigned-issuer created + certificate.cert-manager.io/selfsigned-cert created + +Now, let us wait until the Certificate becomes Ready. An error here might +indicate that the cert-manager-controller is running but keeps failing at the +leader election step. We know that cert-manager-controller is available because +"mpdev verify" only runs this test suite after cert-manager-controller becomes +available. + + $ kubectl wait -n ${NAMESPACE} --for=condition=Ready --timeout=2m certificate selfsigned-cert + certificate.cert-manager.io/selfsigned-cert condition met + +Get the Secret associated to the Certificate: + + $ kubectl get secret -n ${NAMESPACE} selfsigned-cert-tls + NAME TYPE DATA AGE + selfsigned-cert-tls kubernetes.io/tls 3 * (glob) + +Delete the self-signed Issuer and the Certificate: + + $ kubectl delete -n ${NAMESPACE} issuer selfsigned-issuer + issuer.cert-manager.io "selfsigned-issuer" deleted + + $ kubectl delete -n ${NAMESPACE} certificate selfsigned-cert + certificate.cert-manager.io "selfsigned-cert" deleted + + +Create a GoogleCASIssuer and a Certificate: + + $ kubectl apply -n ${NAMESPACE} -f - < apiVersion: cas-issuer.jetstack.io/v1beta1 + > kind: GoogleCASIssuer + > metadata: + > name: googlecas-issuer + > spec: + > project: "todo" + > location: "todo" + > caPoolId: "todo" + > --- + > apiVersion: cert-manager.io/v1 + > kind: Certificate + > metadata: + > name: googlecas-cert + > spec: + > secretName: demo-cert-tls + > commonName: cert-manager.io.demo + > dnsNames: + > - cert-manager.io + > - jetstack.io + > duration: 24h + > renewBefore: 8h + > issuerRef: + > group: cas-issuer.jetstack.io + > kind: GoogleCASIssuer + > name: googlecas-issuer + > EOF + googlecasissuer.cas-issuer.jetstack.io/googlecas-issuer created + certificate.cert-manager.io/googlecas-cert created + +We don't know yet how, as part of this smoke test file, to create a GCP service +account and then create a Kubernetes service account and bind the two together +using the "workload identity" feature. + +Right now, the above GoogleCASIssuer does nothing, and the certificate will +never be issued. This TODO is tracked at +https://github.com/jetstack/jetstack-secure-gcm/issues/19. + +Now, let us delete the GoogleCASIssuer and Certificate. + + $ kubectl delete -n ${NAMESPACE} googlecasissuer googlecas-issuer + googlecasissuer.cas-issuer.jetstack.io "googlecas-issuer" deleted + + $ kubectl delete -n ${NAMESPACE} certificate googlecas-cert + certificate.cert-manager.io "googlecas-cert" deleted diff --git a/smoke-test.yaml b/smoke-test.yaml deleted file mode 100644 index c1bde10..0000000 --- a/smoke-test.yaml +++ /dev/null @@ -1,112 +0,0 @@ -# This smoke test manifest is used in the smoke-test image to run the test -# suite. The testrunner is run in smoke-test.Dockerfile. -# -# To see how this testrunner works, the only way is to read the bash.go: -# https://github.com/GoogleCloudPlatform/marketplace-testrunner/blob/4245fa9/tests/bash.go -actions: - # - name: hang for debugging purposes - # bashTest: - # script: sleep 1200 # 20 minutes - - name: kubectl smoke test - bashTest: - script: kubectl version - expect: - exitCode: - equals: 0 - - name: Create test issuer and self signed cert - bashTest: - script: | - kubectl apply -n ${NAMESPACE} -f - <