1. Installing the AWS Provider#
We will be using the official AWS Provider maintained by Upbound (the creators of Crossplane). Because AWS is massive (over 1000 different resources), Upbound split the AWS Provider into smaller “Families” to save memory in your cluster.
For this series, we will install the provider-aws-s3 and provider-aws-ec2 packages.
To install a provider, you write a standard Kubernetes YAML file targeting the Provider CRD (which was installed in Episode 1).
Create a file named provider-aws.yaml:
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
name: provider-aws-s3
spec:
# This points to the official Upbound OCI registry
package: xpkg.upbound.io/upbound/provider-aws-s3:v1.14.0
---
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
name: provider-aws-ec2
spec:
package: xpkg.upbound.io/upbound/provider-aws-ec2:v1.14.0Apply this to your cluster:
kubectl apply -f provider-aws.yamlVerifying the Provider Installation#
It takes a few minutes for Crossplane to download the package, unpack the binary, and inject the hundreds of CRDs into the cluster.
You can check the status of the providers:
kubectl get providersExpected Terminal Output:
NAME INSTALLED HEALTHY PACKAGE AGE
provider-aws-ec2 True True xpkg.upbound.io/upbound/provider-aws-ec2:v1.14.0 2m
provider-aws-s3 True True xpkg.upbound.io/upbound/provider-aws-s3:v1.14.0 2mOnce INSTALLED and HEALTHY are both True, the cluster has learned how to speak AWS! You can verify this by checking if the bucket CRD exists:
kubectl get crds | grep bucketYou should see buckets.s3.aws.upbound.io listed.
2. Managing Credentials#
The Provider knows how to talk to AWS, but it doesn’t have permission to do so. We must provide it with AWS IAM credentials.
Never hardcode AWS keys into plain text YAML files. We will use native Kubernetes Secrets to store the credentials securely.
Step 1: Create an aws-credentials.txt file#
Create a temporary text file on your laptop containing your AWS Access Keys. Format it like a standard ~/.aws/credentials file:
# aws-credentials.txt
[default]
aws_access_key_id = AKIAIOSFODNN7EXAMPLE
aws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEYStep 2: Inject the text file into a Kubernetes Secret#
Run the following command to create a Kubernetes Secret in the crossplane-system namespace. We are passing the file contents into the credentials key of the Secret.
kubectl create secret generic aws-secret \
-n crossplane-system \
--from-file=credentials=./aws-credentials.txt(You can now delete the aws-credentials.txt file from your laptop).
3. The ProviderConfig#
Now we have a Provider, and we have a Secret. We must link them together. We do this using a ProviderConfig.
A ProviderConfig acts as the authentication configuration for a specific cloud environment. You can create multiple ProviderConfigs (e.g., default, aws-dev-account, aws-prod-account) to manage multiple AWS accounts from a single Crossplane cluster.
Create a file named provider-config.yaml:
apiVersion: aws.upbound.io/v1beta1
kind: ProviderConfig
metadata:
# We name this 'default'. If we don't explicitly specify a ProviderConfig
# on a resource, it will look for this one.
name: default
spec:
credentials:
# Tell Crossplane to look for a Kubernetes Secret
source: Secret
secretRef:
namespace: crossplane-system
name: aws-secret
key: credentialsApply the config:
kubectl apply -f provider-config.yaml4. Alternatives to Static Credentials (IRSA)#
In a real production environment (like AWS EKS), managing static Access Keys is a security risk. They don’t expire, and they must be manually rotated.
If you are running Crossplane on AWS EKS, you should use IAM Roles for Service Accounts (IRSA) instead of a Kubernetes Secret.
With IRSA, you attach an AWS IAM Role directly to the Kubernetes ServiceAccount that the Crossplane Provider Pod uses. The Provider Pod will automatically request short-lived temporary tokens from the AWS Metadata service.
To configure a ProviderConfig for IRSA (or EC2 Instance Metadata), you change the source to InjectedIdentity:
# Example IRSA Configuration (Do not apply if using local kind cluster)
apiVersion: aws.upbound.io/v1beta1
kind: ProviderConfig
metadata:
name: default
spec:
credentials:
source: InjectedIdentityTroubleshooting & Common Errors#
Provider HEALTHY is False- Root Cause: The provider Pod is crashing. This often happens in local
kindclusters if you run out of Docker memory, or if the Kubernetes cluster cannot reach the Upbound registry. - Solution: Run
kubectl get pods -n crossplane-systemand look for pods prefixed withprovider-aws-*. Check their logs usingkubectl logs <pod-name>.
- Root Cause: The provider Pod is crashing. This often happens in local
cannot create resource "providerconfigs"- Root Cause: You tried to apply the
ProviderConfigYAML before the Provider was fully installed andHEALTHY. TheProviderConfigCRD is injected by the Provider itself! - Solution: Wait for
kubectl get providersto showTruefor both columns, then re-apply the ProviderConfig.
- Root Cause: You tried to apply the
Conclusion & Next Steps#
Your Kubernetes cluster is now fully weaponized. It has the Crossplane engine, the AWS Provider schemas, and the IAM credentials required to modify physical cloud infrastructure.
In Episode 3: Managed Resources (MR), we will write our first infrastructure YAML file, provision a physical AWS S3 bucket directly via kubectl, and witness the true power of the continuous reconciliation loop.

