Adds support for Workload Identity, with which credentials no longer
need to be present in Secrets.
If `InjectedIdentity` is specified, a token source for application
default credentials by a GCP Service Account, which is specified in the
`iam.gke.io/gcp-service-account` annotation of a provider's Kubernetes
Service Account.
Tested this in the following environment and process.
```
$ kubectl version --short
Client Version: v1.20.7
Server Version: v1.20.12-gke.1500
```
```
$ gcloud container clusters describe $CLUSTER --format="value(workloadIdentityConfig.workloadPool)"
$PROJECT_ID.svc.id.goog
```
```
$ kubectl get deploy crossplane \
-o jsonpath="{.spec.template.spec.containers[*].image}" \
-n crossplane-system
crossplane/crossplane:v1.6.2
```
Created a `Provider` and `ProviderConfig` with `InjectedIdentity` and
then created a `Topic` managed resource:
```
$ cat <<EOF | kubectl apply -f -
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
name: gcp-provider
spec:
package: $PACKAGE # Use this version
---
apiVersion: gcp.crossplane.io/v1beta1
kind: ProviderConfig
metadata:
name: default
spec:
projectID: $PROJECT_ID
credentials:
source: InjectedIdentity
EOF
$ cat <<EOF | kubectl apply -f -
apiVersion: pubsub.gcp.crossplane.io/v1alpha1
kind: Topic
metadata:
name: foo
spec:
forProvider: {}
EOF
```
Note that Pods are emitting authentication errors until Workload
Identity is configured:
```console
$ kubectl logs gcp-provider-f2edfcc2cd84-f68bc774f-7qscf
// ...
2022-02-06T20:07:06.014Z DEBUG provider-gcp Cannot create
external resource {"controller":
"managed/topic.pubsub.gcp.crossplane.io", "request": "/foo", "uid":
"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", "version": "123456789",
"external-name": "foo", "error": "cannot create Topic: googleapi: Error
403: User not authorized to perform this action., forbidden"}
```
Ensured the Service Account is specified in Deployment though it's
obvious:
```
$ kubectl get sa -o custom-columns=":metadata.name" | grep 'gcp-provider'
gcp-provider-xxxxxxxxxxxx
$ kubectl get deploy gcp-provider-xxxxxxxxxxxx \
-o jsonpath="{.spec.template.spec.serviceAccountName}" \
gcp-provider-xxxxxxxxxxxx
```
Created a GCP Service Account and configured Workload Identity:
```
$ gcloud iam service-accounts create crossplane
$ gcloud projects add-iam-policy-binding $PROJECT_ID \
--member
"serviceAccount:crossplane@$PROJECT_ID.iam.gserviceaccount.com" \
--role roles/admin
$ gcloud iam service-accounts add-iam-policy-binding \
crossplane@$PROJECT_ID.iam.gserviceaccount.com \
--role roles/iam.workloadIdentityUser \
--member "serviceAccount:$PROJECT_ID.svc.id.goog[crossplane-system/gcp-provider-xxxxxxxxxxxx]"
$ kubectl annotate sa gcp-provider-xxxxxxxxxxxx \
iam.gke.io/gcp-service-account=crossplane@$PROJECT_ID.iam.gserviceaccount.com
```
Waited for a little while and then confirmed it was successfully created:
```
$ gcloud pubsub topics describe foo
name: projects/$PROJECT_ID/topics/foo
```
Note that since Service Accounts managed by a controller are named the
same as the current `ProviderRevision` and they are inconstant, it's
necessary to fix a name for production use cases.
Signed-off-by: micnncim <micnncim@gmail.com>