Providers are the meat around Crossplane’s bones, and they are used to extend the capabilities of Crossplane. When Crossplane is installed, it doesn't have any capabilities to interact with external systems. A core Crossplane pod will only watch the following resources.
compositeresourcedefinitions.apiextensions.crossplane.io compositionrevisions.apiextensions.crossplane.io compositions.apiextensions.crossplane.io configurationrevisions.pkg.crossplane.io configurations.pkg.crossplane.io controllerconfigs.pkg.crossplane.io locks.pkg.crossplane.io providerrevisions.pkg.crossplane.io providers.pkg.crossplane.io storeconfigs.secrets.crossplane.io When you install a provider, a new pod is created to Crossplane's installation namespace. This pod is a Kubernetes Controller that watches the CRDs that are also installed as part of the provider package.
To find out what different kinds of providers are available, you can check the Upbound Marketplace and crossplane-contrib repository. For this series, we are going to work with the following providers:
Those GCP providers are installed from the provider-family-gcp package. These provider-family packages are special packages that allow you to install only the provider packages you need instead of installing everything, which would mean 343 CRDs if you install the provider-gcp package instead. Crossplane also states:
On average, 30 CRDs are used from Provider packages.
Looking at the average number, you would still have ~313 CRDs in the cluster that aren't used 🤯.
Install the providers
cat <<EOF | kubectl apply --filename=- apiVersion: pkg.crossplane.io/v1 kind: Provider metadata: name: provider-gcp-storage spec: package: xpkg.upbound.io/upbound/provider-gcp-storage:v0.36.0 --- apiVersion: pkg.crossplane.io/v1 kind: Provider metadata: name: provider-gcp-cloudplatform spec: package: xpkg.upbound.io/upbound/provider-gcp-cloudplatform:v0.36.0 --- apiVersion: pkg.crossplane.io/v1 kind: Provider metadata: name: provider-terraform spec: package: xpkg.upbound.io/upbound/provider-terraform:v0.10.0 EOF After a little while, you should see the providers installed and in a healthy state
kubectl get provider --- NAME INSTALLED HEALTHY PACKAGE AGE provider-gcp-cloudplatform True True xpkg.upbound.io/upbound/provider-gcp-cloudplatform:v0.36.0 116s provider-gcp-storage True True xpkg.upbound.io/upbound/provider-gcp-storage:v0.36.0 116s provider-terraform True True xpkg.upbound.io/upbound/provider-terraform:v0.10.0 116s upbound-provider-family-gcp True True xpkg.upbound.io/upbound/provider-family-gcp:v0.37.0 107s Now the providers are installed and ready, we need to set up the ProviderConfig, which configures the credentials for the provider to be able to interact with external systems, in this case, with Google Cloud. You can have multiple ProviderConfigs and reference them in managed resources using providerConfigRef. ProviderConfigs are cluster-scoped resources.
You can set up a ProviderConfig per tenant when you have a multi-tenant cluster. When creating compositions, you could patch the value of providerConfigRef in managed resources with a value of spec.claimRef.namespace, which points to the namespace where the XRC was created.
Every provider has their own individual settings available when it comes to ProviderConfig. For the GCP provider, you can find all the available configuration options here and for Terraform provider here. If you need to override Controller related settings eg. ServiceAccount you can use ControllerConfig for that.
In upcoming chapters, we will create resources in Google Cloud that involve creating a bucket, serviceaccount, iam-binding, and serviceaccountkey. Use the following to configure a new service account with needed permissions in GCP:
# GCP Project ID PROJECT_ID="" gcloud iam service-accounts create crossplane-sa-demo --display-name "Crossplane Service Account Demo" gcloud projects add-iam-policy-binding $PROJECT_ID --member serviceAccount:crossplane-sa-demo@$PROJECT_ID.iam.gserviceaccount.com --role roles/storage.admin gcloud projects add-iam-policy-binding $PROJECT_ID --member serviceAccount:crossplane-sa-demo@$PROJECT_ID.iam.gserviceaccount.com --role roles/iam.serviceAccountAdmin gcloud projects add-iam-policy-binding $PROJECT_ID --member serviceAccount:crossplane-sa-demo@$PROJECT_ID.iam.gserviceaccount.com --role roles/iam.serviceAccountKeyAdmin gcloud projects add-iam-policy-binding $PROJECT_ID --member serviceAccount:crossplane-sa-demo@$PROJECT_ID.iam.gserviceaccount.com --role roles/storage.iamMember Create a service account key:
gcloud iam service-accounts keys create credentials.json --iam-account=crossplane-sa-demo@$PROJECT_ID.iam.gserviceaccount.com Create a Kubernetes secret in crossplane-system namespace that contains the previously created credentials:
kubectl create secret generic gcp-creds --from-file=creds=./credentials.json -n crossplane-system Create ProviderConfig that uses these credentials:
cat <<EOF | kubectl apply --filename=- apiVersion: gcp.upbound.io/v1beta1 kind: ProviderConfig metadata: name: default spec: projectID: $PROJECT_ID credentials: source: Secret secretRef: name: gcp-creds namespace: crossplane-system key: creds EOF If you run this inside GKE, using the Workload Identity for authentication is much better. You can find detailed instructions for it here.
You can also read the secret from the filesystem using fs. This might come in handy in cases where you are leveraging, for example, Hashicorp Vault with Vault Agent sidecar to inject secrets to pods. Here is a quick example of how you would configure it without going into too much detail about how to work with Vault Agent Injector:
apiVersion: pkg.crossplane.io/v1alpha1 kind: ControllerConfig metadata: name: gcp-config spec: metadata: annotations: vault.hashicorp.com/agent-inject: "true" vault.hashicorp.com/role: "crossplane-providers" ... --- apiVersion: pkg.crossplane.io/v1 kind: Provider metadata: name: provider-gcp-storage spec: package: xpkg.upbound.io/upbound/provider-gcp-storage:v0.36.0 controllerConfigRef: name: gcp-config --- apiVersion: gcp.upbound.io/v1beta1 kind: ProviderConfig metadata: name: default spec: projectID: $PROJECT_ID credentials: source: Filesystem fs: path: /vault/secrets/gcp-creds Now we can quickly test that everything is working by creating a Bucket resource:
cat <<EOF | kubectl apply --filename=- apiVersion: storage.gcp.upbound.io/v1beta1 kind: Bucket metadata: name: ps-bucket-${RANDOM} spec: forProvider: location: US EOF After a little while, you should see the bucket resource ready and synced:
kubectl get bucket --- NAME READY SYNCED EXTERNAL-NAME AGE bucket-crossplane-demo-30855 True True bucket-crossplane-demo-30855 15m At this point, we are ready to start working with GCP using Crossplane. I will go through setting up the Terraform provider configs later in the series when it's time to start working with it.
Remember to delete the test bucket resource:
kubectl delete bucket <bucket_name> The next chapter quickly reviews available configuration options for managed resources.

Top comments (0)