Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .prettierrc.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Since our schema.yaml is quite big, we want to use a good linter:
# npm i -g prettier
# prettier --write schema.yaml
printWidth: 9999
180 changes: 148 additions & 32 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,76 +1,192 @@

# jsp-gcm
=======

# deployer
**Content:**

## Update upstream cert-manager chart version
- [Installing and manually testing the deployer](#installing-and-manually-testing-the-deployer)
- [Testing and releasing the deployer using Google Cloud Build](#testing-and-releasing-the-deployer-using-google-cloud-build)
- [Updating the upstream cert-manager chart version](#updating-the-upstream-cert-manager-chart-version)

From
[building-deployer-helm.md](https://github.com/GoogleCloudPlatform/marketplace-k8s-app-tools/blob/master/docs/building-deployer-helm.md),
bump the version of the cert-manager chart in requirements.yaml. Then:
## Installing and manually testing the deployer

In order to have the google-cas-issuer working, we need to enable [workload
identity](https://cloud.google.com/kubernetes-engine/docs/how-to/workload-identity).
Let's create a cluster that has the workload identity enabled:

```sh
helm repo add jetstack https://charts.jetstack.io
helm dependency build chart/jetstacksecure-mp
gcloud container clusters create foo --region us-east1 --num-nodes=1 --preemptible \
--workload-pool=$(gcloud config get-value project | tr ':' '/').svc.id.goog
```

=======
## Test
Re-publish the images to the project:

```sh
export REGISTRY=gcr.io/$(gcloud config get-value project | tr ':' '/')
export APP_NAME=jetstack-secure

docker pull quay.io/jetstack/cert-manager-controller:v1.1.0
docker pull quay.io/jetstack/cert-manager-cainjector:v1.1.0
docker pull quay.io/jetstack/cert-manager-webhook:v1.1.0
docker tag quay.io/jetstack/cert-manager-controller:v1.1.0 $REGISTRY/$APP_NAME/cert-manager-controller:v1.1.0
docker tag quay.io/jetstack/cert-manager-cainjector:v1.1.0 $REGISTRY/$APP_NAME/cert-manager-cainjector:v1.1.0
docker tag quay.io/jetstack/cert-manager-webhook:v1.1.0 $REGISTRY/$APP_NAME/cert-manager-webhook:v1.1.0
docker push $REGISTRY/$APP_NAME/cert-manager-controller:v1.1.0
docker push $REGISTRY/$APP_NAME/cert-manager-cainjector:v1.1.0
docker push $REGISTRY/$APP_NAME/cert-manager-webhook:v1.1.0
docker pull quay.io/jetstack/cert-manager-google-cas-issuer:0.1.0
docker tag quay.io/jetstack/cert-manager-controller:v1.1.0 $REGISTRY/$APP_NAME/cert-manager-controller:1.1.0
docker tag quay.io/jetstack/cert-manager-cainjector:v1.1.0 $REGISTRY/$APP_NAME/cert-manager-cainjector:1.1.0
docker tag quay.io/jetstack/cert-manager-webhook:v1.1.0 $REGISTRY/$APP_NAME/cert-manager-webhook:1.1.0
docker tag quay.io/jetstack/cert-manager-google-cas-issuer:latest $REGISTRY/$APP_NAME/cert-manager-google-cas-issuer:0.1.0
docker push $REGISTRY/$APP_NAME/cert-manager-controller:1.1.0
docker push $REGISTRY/$APP_NAME/cert-manager-cainjector:1.1.0
docker push $REGISTRY/$APP_NAME/cert-manager-webhook:1.1.0
docker push $REGISTRY/$APP_NAME/cert-manager-google-cas-issuer:0.1.0
```

> Note: although cert-manager's tags are of the form "v1.1.0", we chose to
> use tags of the form "1.1.0" for the Google Marketplace for the sake of
> consistency.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it's a choice. I think GCM enforces that the version be a semver without any prefix.


# Install mpdev:
docker run gcr.io/cloud-marketplace-tools/k8s/dev cat /scripts/dev > /tmp/mpdev && install /tmp/mpdev ~/bin
Then, build and push the deployer image:

kubectl create namespace test
```sh
docker build --tag $REGISTRY/$APP_NAME/deployer .
docker push $REGISTRY/$APP_NAME/deployer
mpdev install --deployer=$REGISTRY/$APP_NAME/deployer --parameters='{"name": "test", "namespace": "test"}'
```

## Google Cloud Build
Finally, use `mpdev` to install jetstack-secure to the `test-ns` namespace:

```sh
# If you don't have it already, install mpdev:
docker run gcr.io/cloud-marketplace-tools/k8s/dev cat /scripts/dev > /tmp/mpdev && install /tmp/mpdev ~/bin

kubectl create ns test-ns
kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/marketplace-k8s-app-tools/master/crd/app-crd.yaml
mpdev install --deployer=$REGISTRY/$APP_NAME/deployer --parameters='{"name": "test-ns", "namespace": "test"}'
```

Now, we need to have access to a CAS root. To create a "root" certificate
authority as well as an intermediate certificate authority ("subordinate")
in your current Google project, run:

```sh
gcloud config set privateca/location us-east1
gcloud beta privateca roots create my-ca --subject="CN=root,O=my-ca"
gcloud beta privateca subordinates create my-sub-ca --issuer=my-ca --location us-east1 --subject="CN=intermediate,O=my-ca,OU=my-sub-ca"
```

> It is recommended to create subordinate CAs for signing leaf
> certificates. See the [official
> documentation](https://cloud.google.com/certificate-authority-service/docs/creating-certificate-authorities).

You can deploy the Google Market Place images and the deployer to
`gcr.io/<PROJECT>/cert-manager` using `gcloud builds` as follows:
At this point, the Kubernetes service account created by `mpdev` still does
not have sufficient privileges in order to access the Google CAS API. We
have to "bind" the Kubernetes service account with a new GCP service
account that will have access to the CAS API.

```sh
export GKE_CLUSTER_NAME=foo
export GKE_CLUSTER_LOCATION=us-east1
gcloud container clusters create $GKE_CLUSTER_NAME --region $GKE_CLUSTER_LOCATION --num-nodes=1 --preemptible
gcloud iam service-accounts create sa-google-cas-issuer
gcloud beta privateca subordinates add-iam-policy-binding my-sub-ca \
--role=roles/privateca.certificateRequester \
--member=serviceAccount:sa-google-cas-issuer@$(gcloud config get-value project | tr ':' '/').iam.gserviceaccount.com
gcloud iam service-accounts add-iam-policy-binding sa-google-cas-issuer@$(gcloud config get-value project | tr ':' '/').iam.gserviceaccount.com \
--role roles/iam.workloadIdentityUser \
--member "serviceAccount:$(gcloud config get-value project | tr ':' '/').svc.id.goog[test-ns/test-google-cas-issuer-serviceaccount-name]"
kubectl annotate serviceaccount -n test-ns test-google-cas-issuer-serviceaccount-name \
iam.gke.io/gcp-service-account=sa-google-cas-issuer@$(gcloud config get-value project | tr ':' '/').iam.gserviceaccount.com
```

gcloud builds submit --timeout 1800s --config cloudbuild.yaml \
--substitutions _CLUSTER_NAME=$GKE_CLUSTER_NAME,_CLUSTER_LOCATION=$GKE_CLUSTER_LOCATION
You can now create an issuer and a certificate:

```sh
cat <<EOF | tee /dev/stderr | kubectl apply -f -
apiVersion: cas-issuer.jetstack.io/v1alpha1
kind: GoogleCASIssuer
metadata:
name: googlecasissuer
spec:
project: $(gcloud config get-value project | tr ':' '/')
location: $(gcloud config get-value privateca/location | tr ':' '/')
certificateAuthorityID: my-sub-ca
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: demo-certificate
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: googlecasissuer
EOF
```

This will also verify the application using the [Google Cloud Marketplace verification tool](https://github.com/GoogleCloudPlatform/marketplace-k8s-app-tools/blob/c5899a928a2ac8d5022463c82823284a9e63b177/scripts/verify).
You can check that the certificate has been issued with:

```sh
% kubectl describe cert demo-certificate
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Issuing 20s cert-manager Issuing certificate as Secret was previously issued by GoogleCASIssuer.cas-issuer.jetstack.io/googlecasissuer-sample
Normal Reused 20s cert-manager Reusing private key stored in existing Secret resource "demo-cert-tls"
Normal Requested 20s cert-manager Created new CertificateRequest resource "demo-certificate-v2rwr"
Normal Issuing 20s cert-manager The certificate has been successfully issued
```

## Testing and releasing the deployer using Google Cloud Build

We use `gcloud builds` in order to automate the release process. Cloud
Build re-publishes the cert-manager images to your project and builds,
tests and pushs the deployer image.

Requirements before running `gcloud builds`:

1. Go to [IAM and Admin > Permissions for
1. You need a GKE cluster with
[workload-identity](https://cloud.google.com/kubernetes-engine/docs/how-to/workload-identity)
enabled. You can either update your existing cluster or create a new
cluster with workload identity enabled with this command:

```sh
export GKE_CLUSTER_NAME=foo
export GKE_CLUSTER_LOCATION=us-east1
gcloud container clusters create $GKE_CLUSTER_NAME --region $GKE_CLUSTER_LOCATION --num-nodes=1 --preemptible \
--workload-pool=$(gcloud config get-value project | tr ':' '/').svc.id.goog
```

2. Go to [IAM and Admin > Permissions for
project](https://console.cloud.google.com/iam-admin/iam) and configure
the `[email protected]` service account with the
following roles so that it has permission to deploy RBAC configuration
to the target cluster and to publish it to a bucket:
- `Cloud Build Service Agent`
- `Kubernetes Engine Admin`
- `Storage Object Admin`
2. Create a bucket that has the same name as your project. To create it,

3. Create a bucket that has the same name as your project. To create it,
run:

```sh
gsutil mb gs://$(gcloud config get-value project | tr ':' '/')
```

Then, you can trigger a build:

```sh
gcloud builds submit --timeout 1800s --config cloudbuild.yaml \
--substitutions _CLUSTER_NAME=$GKE_CLUSTER_NAME,_CLUSTER_LOCATION=$GKE_CLUSTER_LOCATION
```

This will also verify the application using the [Google Cloud Marketplace verification tool](https://github.com/GoogleCloudPlatform/marketplace-k8s-app-tools/blob/c5899a928a2ac8d5022463c82823284a9e63b177/scripts/verify).

## Updating the upstream cert-manager chart version

From
[building-deployer-helm.md](https://github.com/GoogleCloudPlatform/marketplace-k8s-app-tools/blob/master/docs/building-deployer-helm.md),
bump the version of the cert-manager chart in requirements.yaml. Then:

```sh
helm repo add jetstack https://charts.jetstack.io
helm dependency build chart/jetstacksecure-mp
```
10 changes: 9 additions & 1 deletion chart/jetstacksecure-mp/Chart.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
apiVersion: v2
engine: gotpl
name: jetstacksecure-mp
version: 1.1.0
version: 1.0.0
dependencies:
- name: cert-manager
version: 1.1.0
appVersion: v1.1.0
repository: https://charts.jetstack.io
- name: google-cas-issuer
appVersion: 0.1.0
repository: ./charts/google-cas-issuer
17 changes: 17 additions & 0 deletions chart/jetstacksecure-mp/charts/google-cas-issuer/Chart.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
apiVersion: "v2"
name: "google-cas-issuer"
version: "1.0.0"
kubeVersion: ">= 1.16.0"
description: "Install the cert-manager Google CAS issuer"
type: "application"
keywords:
- "google-cas"
- "google-private-ca"
home: "https://github.com/jetstack/google-cas-issuer"
sources:
- "https://github.com/jetstack/google-cas-issuer"
maintainers:
- name: "Jetstack Ltd"
email: "[email protected]"
url: "https://www.jetstack.io/"
appVersion: "0.1.0"
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
The Google CAS issuer for cert-manager is now installed.

To finish the installation, please follow these steps:


1. Make sure your cluster has the "workload identity" feature turned on. If\
you are not sure, you can try enabling it with:

gcloud container clusters update CLUSTER_NAME --workload-pool=$(gcloud config get-value project | tr ':' '/').svc.id.goog

2. Make sure to have a Google CAS root or subordinate CA created. For example,
you can create one with:

gcloud config set privateca/location us-east1
gcloud beta privateca roots create my-ca --subject="CN=my-ca,O=my-org"

3. Create a GCP service account and bind it to the Kubernetes service account
that was deployed in this Helm release:

gcloud iam service-accounts create sa-google-cas-issuer
gcloud beta privateca subordinates add-iam-policy-binding my-ca \
--role=roles/privateca.certificateRequester \
--member=serviceAccount:sa-google-cas-issuer@$(gcloud config get-value project | tr ':' '/').iam.gserviceaccount.com
gcloud iam service-accounts add-iam-policy-binding sa-google-cas-issuer@$(gcloud config get-value project | tr ':' '/').iam.gserviceaccount.com \
--role roles/iam.workloadIdentityUser \
--member "serviceAccount:$(gcloud config get-value project | tr ':' '/').svc.id.goog[{{ .Release.Namespace }}/{{ .Values.serviceAccount.name }}]"
kubectl annotate serviceaccount -n {{ .Release.Namespace }} {{ .Values.serviceAccount.name }} \
iam.gke.io/gcp-service-account=sa-google-cas-issuer@$(gcloud config get-value project | tr ':' '/').iam.gserviceaccount.com

4. Finally, you can create your GoogleCASIssuer and a Certificate:

cat <<EOF | tee /dev/stderr | kubectl apply -f -
apiVersion: cas-issuer.jetstack.io/v1alpha1
kind: GoogleCASIssuer
metadata:
name: googlecasissuer
spec:
project: $(gcloud config get-value project | tr ':' '/')
location: $(gcloud config get-value privateca/location | tr ':' '/')
certificateAuthorityID: my-ca
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: demo-certificate
spec:
secretName: demo-cert-tls
commonName: cert-manager.io.demo
dnsNames:
- cert-manager.io
duration: 24h
renewBefore: 8h
issuerRef:
group: cas-issuer.jetstack.io
kind: GoogleCASIssuer
name: googlecasissuer
EOF

5. Finally, check that the Certificate has been issued properly:

kubectl describe demo-certificate
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
{{/*
Expand the name of the chart.
*/}}
{{- define "google-cas-issuer.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}

{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
If release name contains chart name it will be used as a full name.
*/}}
{{- define "google-cas-issuer.fullname" -}}
{{- if .Values.fullnameOverride }}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- $name := default .Chart.Name .Values.nameOverride }}
{{- if contains $name .Release.Name }}
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- end }}
{{- end }}

{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "google-cas-issuer.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}

{{/*
Common labels
*/}}
{{- define "google-cas-issuer.labels" -}}
helm.sh/chart: {{ include "google-cas-issuer.chart" . }}
{{ include "google-cas-issuer.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}
{{- end }}

{{/*
Selector labels
*/}}
{{- define "google-cas-issuer.selectorLabels" -}}
app.kubernetes.io/name: {{ include "google-cas-issuer.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/component: "controller"
{{- end }}

{{/*
Create the name of the service account to use
*/}}
{{- define "google-cas-issuer.serviceAccountName" -}}
{{- if .Values.serviceAccount.create }}
{{- default (include "google-cas-issuer.fullname" .) .Values.serviceAccount.name }}
{{- else }}
{{- default "default" .Values.serviceAccount.name }}
{{- end }}
{{- end }}
Loading