Connect Crossplane to AWS to create and manage cloud resources from Kubernetes with
provider-upjet-aws.

This guide is in two parts:

  • Part 1 walks through installing Crossplane, configuring the provider to authenticate to AWS and creating a Managed Resource in AWS directly from your Kubernetes cluster. This shows Crossplane can communicate with AWS.
  • Part 2 shows how to build and access a custom API with Crossplane.

Prerequisites

This quickstart requires:

  • a Kubernetes cluster with at least 2 GB of RAM
  • permissions to create pods and secrets in the Kubernetes cluster
  • Helm version v3.2.0 or later
  • an AWS account with permissions to create an S3 storage bucket
  • AWS access keys

Install Crossplane

Crossplane installs into an existing Kubernetes cluster.

Tip
If you don’t have a Kubernetes cluster create one locally with Kind.

Install the Crossplane Helm chart

Helm enables Crossplane to install all its Kubernetes components through a Helm Chart.

Enable the Crossplane Helm Chart repository:

1helm repo add \ 2crossplane-stable https://charts.crossplane.io/stable 3helm repo update 

Run the Helm dry-run to see all the Crossplane components Helm installs.

1helm install crossplane \ 2crossplane-stable/crossplane \ 3--dry-run --debug \ 4--namespace crossplane-system \ 5--create-namespace 

 1helm install crossplane \  2crossplane-stable/crossplane \  3--dry-run --debug \  4--namespace crossplane-system \  5--create-namespace  6install.go:214: [debug] Original chart version: ""  7install.go:216: [debug] setting version to >0.0.0-0  8install.go:231: [debug] CHART PATH: /Users/plumbis/Library/Caches/helm/repository/crossplane-1.15.0.tgz  9  10NAME: crossplane  11LAST DEPLOYED: Mon Feb 12 14:46:15 2024  12NAMESPACE: default  13STATUS: pending-install  14REVISION: 1  15TEST SUITE: None  16USER-SUPPLIED VALUES:  17{}  18  19COMPUTED VALUES:  20affinity: {}  21args: []  22configuration:  23 packages: []  24customAnnotations: {}  25customLabels: {}  26deploymentStrategy: RollingUpdate  27extraEnvVarsCrossplane: {}  28extraEnvVarsRBACManager: {}  29extraObjects: []  30extraVolumeMountsCrossplane: {}  31extraVolumesCrossplane: {}  32function:  33 packages: []  34hostNetwork: false  35image:  36 pullPolicy: IfNotPresent  37 repository: xpkg.crossplane.io/crossplane/crossplane  38 tag: ""  39imagePullSecrets: {}  40leaderElection: true  41metrics:  42 enabled: false  43nodeSelector: {}  44packageCache:  45 configMap: ""  46 medium: ""  47 pvc: ""  48 sizeLimit: 20Mi  49podSecurityContextCrossplane: {}  50podSecurityContextRBACManager: {}  51priorityClassName: ""  52provider:  53 packages: []  54rbacManager:  55 affinity: {}  56 args: []  57 deploy: true  58 leaderElection: true  59 nodeSelector: {}  60 replicas: 1  61 skipAggregatedClusterRoles: false  62 tolerations: []  63registryCaBundleConfig:  64 key: ""  65 name: ""  66replicas: 1  67resourcesCrossplane:  68 limits:  69 cpu: 100m  70 memory: 512Mi  71 requests:  72 cpu: 100m  73 memory: 256Mi  74resourcesRBACManager:  75 limits:  76 cpu: 100m  77 memory: 512Mi  78 requests:  79 cpu: 100m  80 memory: 256Mi  81securityContextCrossplane:  82 allowPrivilegeEscalation: false  83 readOnlyRootFilesystem: true  84 runAsGroup: 65532  85 runAsUser: 65532  86securityContextRBACManager:  87 allowPrivilegeEscalation: false  88 readOnlyRootFilesystem: true  89 runAsGroup: 65532  90 runAsUser: 65532  91serviceAccount:  92 customAnnotations: {}  93tolerations: []  94webhooks:  95 enabled: true  96  97HOOKS:  98MANIFEST:  99---  100# Source: crossplane/templates/rbac-manager-serviceaccount.yaml  101apiVersion: v1  102kind: ServiceAccount  103metadata:  104 name: rbac-manager  105 namespace: default  106 labels:  107 app: crossplane  108 helm.sh/chart: crossplane-1.15.0  109 app.kubernetes.io/managed-by: Helm  110 app.kubernetes.io/component: cloud-infrastructure-controller  111 app.kubernetes.io/part-of: crossplane  112 app.kubernetes.io/name: crossplane  113 app.kubernetes.io/instance: crossplane  114 app.kubernetes.io/version: "1.15.0"  115---  116# Source: crossplane/templates/serviceaccount.yaml  117apiVersion: v1  118kind: ServiceAccount  119metadata:  120 name: crossplane  121 namespace: default  122 labels:  123 app: crossplane  124 helm.sh/chart: crossplane-1.15.0  125 app.kubernetes.io/managed-by: Helm  126 app.kubernetes.io/component: cloud-infrastructure-controller  127 app.kubernetes.io/part-of: crossplane  128 app.kubernetes.io/name: crossplane  129 app.kubernetes.io/instance: crossplane  130 app.kubernetes.io/version: "1.15.0"  131---  132# Source: crossplane/templates/secret.yaml  133# The reason this is created empty and filled by the init container is we want  134# to manage the lifecycle of the secret via Helm. This way whenever Crossplane  135# is deleted, the secret is deleted as well.  136apiVersion: v1  137kind: Secret  138metadata:  139 name: crossplane-root-ca  140 namespace: default  141type: Opaque  142---  143# Source: crossplane/templates/secret.yaml  144# The reason this is created empty and filled by the init container is we want  145# to manage the lifecycle of the secret via Helm. This way whenever Crossplane  146# is deleted, the secret is deleted as well.  147apiVersion: v1  148kind: Secret  149metadata:  150 name: crossplane-tls-server  151 namespace: default  152type: Opaque  153---  154# Source: crossplane/templates/secret.yaml  155# The reason this is created empty and filled by the init container is we want  156# to manage the lifecycle of the secret via Helm. This way whenever Crossplane  157# is deleted, the secret is deleted as well.  158apiVersion: v1  159kind: Secret  160metadata:  161 name: crossplane-tls-client  162 namespace: default  163type: Opaque  164---  165# Source: crossplane/templates/clusterrole.yaml  166apiVersion: rbac.authorization.k8s.io/v1  167kind: ClusterRole  168metadata:  169 name: crossplane  170 labels:  171 app: crossplane  172 helm.sh/chart: crossplane-1.15.0  173 app.kubernetes.io/managed-by: Helm  174 app.kubernetes.io/component: cloud-infrastructure-controller  175 app.kubernetes.io/part-of: crossplane  176 app.kubernetes.io/name: crossplane  177 app.kubernetes.io/instance: crossplane  178 app.kubernetes.io/version: "1.15.0"  179aggregationRule:  180 clusterRoleSelectors:  181 - matchLabels:  182 rbac.crossplane.io/aggregate-to-crossplane: "true"  183---  184# Source: crossplane/templates/clusterrole.yaml  185apiVersion: rbac.authorization.k8s.io/v1  186kind: ClusterRole  187metadata:  188 name: crossplane:system:aggregate-to-crossplane  189 labels:  190 app: crossplane  191 helm.sh/chart: crossplane-1.15.0  192 app.kubernetes.io/managed-by: Helm  193 app.kubernetes.io/component: cloud-infrastructure-controller  194 app.kubernetes.io/part-of: crossplane  195 app.kubernetes.io/name: crossplane  196 app.kubernetes.io/instance: crossplane  197 app.kubernetes.io/version: "1.15.0"  198 crossplane.io/scope: "system"  199 rbac.crossplane.io/aggregate-to-crossplane: "true"  200rules:  201- apiGroups:  202 - ""  203 resources:  204 - events  205 verbs:  206 - create  207 - update  208 - patch  209 - delete  210- apiGroups:  211 - apiextensions.k8s.io  212 resources:  213 - customresourcedefinitions  214 - customresourcedefinitions/status  215 verbs:  216 - "*"  217- apiGroups:  218 - ""  219 resources:  220 - secrets  221 verbs:  222 - get  223 - list  224 - watch  225 - create  226 - update  227 - patch  228 - delete  229- apiGroups:  230 - ""  231 resources:  232 - serviceaccounts  233 - services  234 verbs:  235 - "*"  236- apiGroups:  237 - apiextensions.crossplane.io  238 - pkg.crossplane.io  239 - secrets.crossplane.io  240 resources:  241 - "*"  242 verbs:  243 - "*"  244- apiGroups:  245 - extensions  246 - apps  247 resources:  248 - deployments  249 verbs:  250 - get  251 - list  252 - create  253 - update  254 - patch  255 - delete  256 - watch  257- apiGroups:  258 - ""  259 - coordination.k8s.io  260 resources:  261 - configmaps  262 - leases  263 verbs:  264 - get  265 - list  266 - create  267 - update  268 - patch  269 - watch  270 - delete  271- apiGroups:  272 - admissionregistration.k8s.io  273 resources:  274 - validatingwebhookconfigurations  275 - mutatingwebhookconfigurations  276 verbs:  277 - get  278 - list  279 - create  280 - update  281 - patch  282 - watch  283 - delete  284---  285# Source: crossplane/templates/rbac-manager-allowed-provider-permissions.yaml  286apiVersion: rbac.authorization.k8s.io/v1  287kind: ClusterRole  288metadata:  289 name: crossplane:allowed-provider-permissions  290 labels:  291 app: crossplane  292 helm.sh/chart: crossplane-1.15.0  293 app.kubernetes.io/managed-by: Helm  294 app.kubernetes.io/component: cloud-infrastructure-controller  295 app.kubernetes.io/part-of: crossplane  296 app.kubernetes.io/name: crossplane  297 app.kubernetes.io/instance: crossplane  298 app.kubernetes.io/version: "1.15.0"  299aggregationRule:  300 clusterRoleSelectors:  301 - matchLabels:  302 rbac.crossplane.io/aggregate-to-allowed-provider-permissions: "true"  303---  304# Source: crossplane/templates/rbac-manager-clusterrole.yaml  305apiVersion: rbac.authorization.k8s.io/v1  306kind: ClusterRole  307metadata:  308 name: crossplane-rbac-manager  309 labels:  310 app: crossplane  311 helm.sh/chart: crossplane-1.15.0  312 app.kubernetes.io/managed-by: Helm  313 app.kubernetes.io/component: cloud-infrastructure-controller  314 app.kubernetes.io/part-of: crossplane  315 app.kubernetes.io/name: crossplane  316 app.kubernetes.io/instance: crossplane  317 app.kubernetes.io/version: "1.15.0"  318rules:  319- apiGroups:  320 - ""  321 resources:  322 - events  323 verbs:  324 - create  325 - update  326 - patch  327 - delete  328- apiGroups:  329 - ""  330 resources:  331 - namespaces  332 verbs:  333 - get  334 - list  335 - watch  336- apiGroups:  337 - apps  338 resources:  339 - deployments  340 verbs:  341 - get  342 - list  343 - watch  344# The RBAC manager creates a series of RBAC roles for each namespace it sees.  345# These RBAC roles are controlled (in the owner reference sense) by the namespace.  346# The RBAC manager needs permission to set finalizers on Namespaces in order to  347# create resources that block their deletion when the  348# OwnerReferencesPermissionEnforcement admission controller is enabled.  349# See https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#ownerreferencespermissionenforcement  350- apiGroups:  351 - ""  352 resources:  353 - namespaces/finalizers  354 verbs:  355 - update  356- apiGroups:  357 - apiextensions.crossplane.io  358 resources:  359 - compositeresourcedefinitions  360 verbs:  361 - get  362 - list  363 - watch  364# The RBAC manager creates a series of RBAC cluster roles for each XRD it sees.  365# These cluster roles are controlled (in the owner reference sense) by the XRD.  366# The RBAC manager needs permission to set finalizers on XRDs in order to  367# create resources that block their deletion when the  368# OwnerReferencesPermissionEnforcement admission controller is enabled.  369# See https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#ownerreferencespermissionenforcement  370- apiGroups:  371 - apiextensions.crossplane.io  372 resources:  373 - compositeresourcedefinitions/finalizers  374 verbs:  375 - update  376- apiGroups:  377 - pkg.crossplane.io  378 resources:  379 - providerrevisions  380 verbs:  381 - get  382 - list  383 - watch  384# The RBAC manager creates a series of RBAC cluster roles for each ProviderRevision  385# it sees. These cluster roles are controlled (in the owner reference sense) by the  386# ProviderRevision. The RBAC manager needs permission to set finalizers on  387# ProviderRevisions in order to create resources that block their deletion when the  388# OwnerReferencesPermissionEnforcement admission controller is enabled.  389# See https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#ownerreferencespermissionenforcement  390- apiGroups:  391 - pkg.crossplane.io  392 resources:  393 - providerrevisions/finalizers  394 verbs:  395 - update  396- apiGroups:  397 - apiextensions.k8s.io  398 resources:  399 - customresourcedefinitions  400 verbs:  401 - get  402 - list  403 - watch  404- apiGroups:  405 - rbac.authorization.k8s.io  406 resources:  407 - clusterroles  408 - roles  409 verbs:  410 - get  411 - list  412 - watch  413 - create  414 - update  415 - patch  416 # The RBAC manager may grant access it does not have.  417 - escalate  418- apiGroups:  419 - rbac.authorization.k8s.io  420 resources:  421 - clusterroles  422 verbs:  423 - bind  424- apiGroups:  425 - rbac.authorization.k8s.io  426 resources:  427 - clusterrolebindings  428 verbs:  429 - "*"  430- apiGroups:  431 - ""  432 - coordination.k8s.io  433 resources:  434 - configmaps  435 - leases  436 verbs:  437 - get  438 - list  439 - create  440 - update  441 - patch  442 - watch  443 - delete  444---  445# Source: crossplane/templates/rbac-manager-managed-clusterroles.yaml  446apiVersion: rbac.authorization.k8s.io/v1  447kind: ClusterRole  448metadata:  449 name: crossplane-admin  450 labels:  451 app: crossplane  452 helm.sh/chart: crossplane-1.15.0  453 app.kubernetes.io/managed-by: Helm  454 app.kubernetes.io/component: cloud-infrastructure-controller  455 app.kubernetes.io/part-of: crossplane  456 app.kubernetes.io/name: crossplane  457 app.kubernetes.io/instance: crossplane  458 app.kubernetes.io/version: "1.15.0"  459aggregationRule:  460 clusterRoleSelectors:  461 - matchLabels:  462 rbac.crossplane.io/aggregate-to-admin: "true"  463---  464# Source: crossplane/templates/rbac-manager-managed-clusterroles.yaml  465apiVersion: rbac.authorization.k8s.io/v1  466kind: ClusterRole  467metadata:  468 name: crossplane-edit  469 labels:  470 app: crossplane  471 helm.sh/chart: crossplane-1.15.0  472 app.kubernetes.io/managed-by: Helm  473 app.kubernetes.io/component: cloud-infrastructure-controller  474 app.kubernetes.io/part-of: crossplane  475 app.kubernetes.io/name: crossplane  476 app.kubernetes.io/instance: crossplane  477 app.kubernetes.io/version: "1.15.0"  478aggregationRule:  479 clusterRoleSelectors:  480 - matchLabels:  481 rbac.crossplane.io/aggregate-to-edit: "true"  482---  483# Source: crossplane/templates/rbac-manager-managed-clusterroles.yaml  484apiVersion: rbac.authorization.k8s.io/v1  485kind: ClusterRole  486metadata:  487 name: crossplane-view  488 labels:  489 app: crossplane  490 helm.sh/chart: crossplane-1.15.0  491 app.kubernetes.io/managed-by: Helm  492 app.kubernetes.io/component: cloud-infrastructure-controller  493 app.kubernetes.io/part-of: crossplane  494 app.kubernetes.io/name: crossplane  495 app.kubernetes.io/instance: crossplane  496 app.kubernetes.io/version: "1.15.0"  497aggregationRule:  498 clusterRoleSelectors:  499 - matchLabels:  500 rbac.crossplane.io/aggregate-to-view: "true"  501---  502# Source: crossplane/templates/rbac-manager-managed-clusterroles.yaml  503apiVersion: rbac.authorization.k8s.io/v1  504kind: ClusterRole  505metadata:  506 name: crossplane-browse  507 labels:  508 app: crossplane  509 helm.sh/chart: crossplane-1.15.0  510 app.kubernetes.io/managed-by: Helm  511 app.kubernetes.io/component: cloud-infrastructure-controller  512 app.kubernetes.io/part-of: crossplane  513 app.kubernetes.io/name: crossplane  514 app.kubernetes.io/instance: crossplane  515 app.kubernetes.io/version: "1.15.0"  516aggregationRule:  517 clusterRoleSelectors:  518 - matchLabels:  519 rbac.crossplane.io/aggregate-to-browse: "true"  520---  521# Source: crossplane/templates/rbac-manager-managed-clusterroles.yaml  522apiVersion: rbac.authorization.k8s.io/v1  523kind: ClusterRole  524metadata:  525 name: crossplane:aggregate-to-admin  526 labels:  527 rbac.crossplane.io/aggregate-to-admin: "true"  528 app: crossplane  529 helm.sh/chart: crossplane-1.15.0  530 app.kubernetes.io/managed-by: Helm  531 app.kubernetes.io/component: cloud-infrastructure-controller  532 app.kubernetes.io/part-of: crossplane  533 app.kubernetes.io/name: crossplane  534 app.kubernetes.io/instance: crossplane  535 app.kubernetes.io/version: "1.15.0"  536rules:  537# Crossplane administrators have access to view events.  538- apiGroups: [""]  539 resources: [events]  540 verbs: [get, list, watch]  541# Crossplane administrators must create provider credential secrets, and may  542# need to read or otherwise interact with connection secrets. They may also need  543# to create or annotate namespaces.  544- apiGroups: [""]  545 resources: [secrets, namespaces]  546 verbs: ["*"]  547# Crossplane administrators have access to view the roles that they may be able  548# to grant to other subjects.  549- apiGroups: [rbac.authorization.k8s.io]  550 resources: [clusterroles, roles]  551 verbs: [get, list, watch]  552# Crossplane administrators have access to grant the access they have to other  553# subjects.  554- apiGroups: [rbac.authorization.k8s.io]  555 resources: [clusterrolebindings, rolebindings]  556 verbs: ["*"]  557# Crossplane administrators have full access to built in Crossplane types.  558- apiGroups:  559 - apiextensions.crossplane.io  560 resources: ["*"]  561 verbs: ["*"]  562- apiGroups:  563 - pkg.crossplane.io  564 resources: ["*"]  565 verbs: ["*"]  566# Crossplane administrators have access to view CRDs in order to debug XRDs.  567- apiGroups: [apiextensions.k8s.io]  568 resources: [customresourcedefinitions]  569 verbs: [get, list, watch]  570---  571# Source: crossplane/templates/rbac-manager-managed-clusterroles.yaml  572apiVersion: rbac.authorization.k8s.io/v1  573kind: ClusterRole  574metadata:  575 name: crossplane:aggregate-to-edit  576 labels:  577 rbac.crossplane.io/aggregate-to-edit: "true"  578 app: crossplane  579 helm.sh/chart: crossplane-1.15.0  580 app.kubernetes.io/managed-by: Helm  581 app.kubernetes.io/component: cloud-infrastructure-controller  582 app.kubernetes.io/part-of: crossplane  583 app.kubernetes.io/name: crossplane  584 app.kubernetes.io/instance: crossplane  585 app.kubernetes.io/version: "1.15.0"  586rules:  587# Crossplane editors have access to view events.  588- apiGroups: [""]  589 resources: [events]  590 verbs: [get, list, watch]  591# Crossplane editors must create provider credential secrets, and may need to  592# read or otherwise interact with connection secrets.  593- apiGroups: [""]  594 resources: [secrets]  595 verbs: ["*"]  596# Crossplane editors may see which namespaces exist, but not edit them.  597- apiGroups: [""]  598 resources: [namespaces]  599 verbs: [get, list, watch]  600# Crossplane editors have full access to built in Crossplane types.  601- apiGroups:  602 - apiextensions.crossplane.io  603 resources: ["*"]  604 verbs: ["*"]  605- apiGroups:  606 - pkg.crossplane.io  607 resources: ["*"]  608 verbs: ["*"]  609---  610# Source: crossplane/templates/rbac-manager-managed-clusterroles.yaml  611apiVersion: rbac.authorization.k8s.io/v1  612kind: ClusterRole  613metadata:  614 name: crossplane:aggregate-to-view  615 labels:  616 rbac.crossplane.io/aggregate-to-view: "true"  617 app: crossplane  618 helm.sh/chart: crossplane-1.15.0  619 app.kubernetes.io/managed-by: Helm  620 app.kubernetes.io/component: cloud-infrastructure-controller  621 app.kubernetes.io/part-of: crossplane  622 app.kubernetes.io/name: crossplane  623 app.kubernetes.io/instance: crossplane  624 app.kubernetes.io/version: "1.15.0"  625rules:  626# Crossplane viewers have access to view events.  627- apiGroups: [""]  628 resources: [events]  629 verbs: [get, list, watch]  630# Crossplane viewers may see which namespaces exist.  631- apiGroups: [""]  632 resources: [namespaces]  633 verbs: [get, list, watch]  634# Crossplane viewers have read-only access to built in Crossplane types.  635- apiGroups:  636 - apiextensions.crossplane.io  637 resources: ["*"]  638 verbs: [get, list, watch]  639- apiGroups:  640 - pkg.crossplane.io  641 resources: ["*"]  642 verbs: [get, list, watch]  643---  644# Source: crossplane/templates/rbac-manager-managed-clusterroles.yaml  645apiVersion: rbac.authorization.k8s.io/v1  646kind: ClusterRole  647metadata:  648 name: crossplane:aggregate-to-browse  649 labels:  650 rbac.crossplane.io/aggregate-to-browse: "true"  651 app: crossplane  652 helm.sh/chart: crossplane-1.15.0  653 app.kubernetes.io/managed-by: Helm  654 app.kubernetes.io/component: cloud-infrastructure-controller  655 app.kubernetes.io/part-of: crossplane  656 app.kubernetes.io/name: crossplane  657 app.kubernetes.io/instance: crossplane  658 app.kubernetes.io/version: "1.15.0"  659rules:  660# Crossplane browsers have access to view events.  661- apiGroups: [""]  662 resources: [events]  663 verbs: [get, list, watch]  664# Crossplane browsers have read-only access to compositions and XRDs. This  665# allows them to discover and select an appropriate composition when creating a  666# resource claim.  667- apiGroups:  668 - apiextensions.crossplane.io  669 resources: ["*"]  670 verbs: [get, list, watch]  671---  672# Source: crossplane/templates/clusterrolebinding.yaml  673apiVersion: rbac.authorization.k8s.io/v1  674kind: ClusterRoleBinding  675metadata:  676 name: crossplane  677 labels:  678 app: crossplane  679 helm.sh/chart: crossplane-1.15.0  680 app.kubernetes.io/managed-by: Helm  681 app.kubernetes.io/component: cloud-infrastructure-controller  682 app.kubernetes.io/part-of: crossplane  683 app.kubernetes.io/name: crossplane  684 app.kubernetes.io/instance: crossplane  685 app.kubernetes.io/version: "1.15.0"  686roleRef:  687 apiGroup: rbac.authorization.k8s.io  688 kind: ClusterRole  689 name: crossplane  690subjects:  691- kind: ServiceAccount  692 name: crossplane  693 namespace: default  694---  695# Source: crossplane/templates/rbac-manager-clusterrolebinding.yaml  696apiVersion: rbac.authorization.k8s.io/v1  697kind: ClusterRoleBinding  698metadata:  699 name: crossplane-rbac-manager  700 labels:  701 app: crossplane  702 helm.sh/chart: crossplane-1.15.0  703 app.kubernetes.io/managed-by: Helm  704 app.kubernetes.io/component: cloud-infrastructure-controller  705 app.kubernetes.io/part-of: crossplane  706 app.kubernetes.io/name: crossplane  707 app.kubernetes.io/instance: crossplane  708 app.kubernetes.io/version: "1.15.0"  709roleRef:  710 apiGroup: rbac.authorization.k8s.io  711 kind: ClusterRole  712 name: crossplane-rbac-manager  713subjects:  714- kind: ServiceAccount  715 name: rbac-manager  716 namespace: default  717---  718# Source: crossplane/templates/rbac-manager-managed-clusterroles.yaml  719apiVersion: rbac.authorization.k8s.io/v1  720kind: ClusterRoleBinding  721metadata:  722 name: crossplane-admin  723 labels:  724 app: crossplane  725 helm.sh/chart: crossplane-1.15.0  726 app.kubernetes.io/managed-by: Helm  727 app.kubernetes.io/component: cloud-infrastructure-controller  728 app.kubernetes.io/part-of: crossplane  729 app.kubernetes.io/name: crossplane  730 app.kubernetes.io/instance: crossplane  731 app.kubernetes.io/version: "1.15.0"  732roleRef:  733 apiGroup: rbac.authorization.k8s.io  734 kind: ClusterRole  735 name: crossplane-admin  736subjects:  737- apiGroup: rbac.authorization.k8s.io  738 kind: Group  739 name: crossplane:masters  740---  741# Source: crossplane/templates/service.yaml  742apiVersion: v1  743kind: Service  744metadata:  745 name: crossplane-webhooks  746 namespace: default  747 labels:  748 app: crossplane  749 release: crossplane  750 helm.sh/chart: crossplane-1.15.0  751 app.kubernetes.io/managed-by: Helm  752 app.kubernetes.io/component: cloud-infrastructure-controller  753 app.kubernetes.io/part-of: crossplane  754 app.kubernetes.io/name: crossplane  755 app.kubernetes.io/instance: crossplane  756 app.kubernetes.io/version: "1.15.0"  757spec:  758 selector:  759 app: crossplane  760 release: crossplane  761 ports:  762 - protocol: TCP  763 port: 9443  764 targetPort: 9443  765---  766# Source: crossplane/templates/deployment.yaml  767apiVersion: apps/v1  768kind: Deployment  769metadata:  770 name: crossplane  771 namespace: default  772 labels:  773 app: crossplane  774 release: crossplane  775 helm.sh/chart: crossplane-1.15.0  776 app.kubernetes.io/managed-by: Helm  777 app.kubernetes.io/component: cloud-infrastructure-controller  778 app.kubernetes.io/part-of: crossplane  779 app.kubernetes.io/name: crossplane  780 app.kubernetes.io/instance: crossplane  781 app.kubernetes.io/version: "1.15.0"  782spec:  783 replicas: 1  784 selector:  785 matchLabels:  786 app: crossplane  787 release: crossplane  788 strategy:  789 type: RollingUpdate  790 template:  791 metadata:  792 labels:  793 app: crossplane  794 release: crossplane  795 helm.sh/chart: crossplane-1.15.0  796 app.kubernetes.io/managed-by: Helm  797 app.kubernetes.io/component: cloud-infrastructure-controller  798 app.kubernetes.io/part-of: crossplane  799 app.kubernetes.io/name: crossplane  800 app.kubernetes.io/instance: crossplane  801 app.kubernetes.io/version: "1.15.0"  802 spec:  803 serviceAccountName: crossplane  804 hostNetwork: false  805 initContainers:  806 - image: "xpkg.crossplane.io/crossplane/crossplane:v1.15.0"  807 args:  808 - core  809 - init  810 imagePullPolicy: IfNotPresent  811 name: crossplane-init  812 resources:  813 limits:  814 cpu: 100m  815 memory: 512Mi  816 requests:  817 cpu: 100m  818 memory: 256Mi  819 securityContext:  820 allowPrivilegeEscalation: false  821 readOnlyRootFilesystem: true  822 runAsGroup: 65532  823 runAsUser: 65532  824 env:  825 - name: GOMAXPROCS  826 valueFrom:  827 resourceFieldRef:  828 containerName: crossplane-init  829 resource: limits.cpu  830 divisor: "1"  831 - name: GOMEMLIMIT  832 valueFrom:  833 resourceFieldRef:  834 containerName: crossplane-init  835 resource: limits.memory  836 divisor: "1"  837 - name: POD_NAMESPACE  838 valueFrom:  839 fieldRef:  840 fieldPath: metadata.namespace  841 - name: POD_SERVICE_ACCOUNT  842 valueFrom:  843 fieldRef:  844 fieldPath: spec.serviceAccountName  845 - name: "WEBHOOK_SERVICE_NAME"  846 value: crossplane-webhooks  847 - name: "WEBHOOK_SERVICE_NAMESPACE"  848 valueFrom:  849 fieldRef:  850 fieldPath: metadata.namespace  851 - name: "WEBHOOK_SERVICE_PORT"  852 value: "9443"  853 - name: "TLS_CA_SECRET_NAME"  854 value: crossplane-root-ca  855 - name: "TLS_SERVER_SECRET_NAME"  856 value: crossplane-tls-server  857 - name: "TLS_CLIENT_SECRET_NAME"  858 value: crossplane-tls-client  859 containers:  860 - image: "xpkg.crossplane.io/crossplane/crossplane:v1.15.0"  861 args:  862 - core  863 - start  864 imagePullPolicy: IfNotPresent  865 name: crossplane  866 resources:  867 limits:  868 cpu: 100m  869 memory: 512Mi  870 requests:  871 cpu: 100m  872 memory: 256Mi  873 startupProbe:  874 failureThreshold: 30  875 periodSeconds: 2  876 tcpSocket:  877 port: readyz  878 ports:  879 - name: readyz  880 containerPort: 8081  881 - name: webhooks  882 containerPort: 9443  883 securityContext:  884 allowPrivilegeEscalation: false  885 readOnlyRootFilesystem: true  886 runAsGroup: 65532  887 runAsUser: 65532  888 env:  889 - name: GOMAXPROCS  890 valueFrom:  891 resourceFieldRef:  892 containerName: crossplane  893 resource: limits.cpu  894 divisor: "1"  895 - name: GOMEMLIMIT  896 valueFrom:  897 resourceFieldRef:  898 containerName: crossplane  899 resource: limits.memory  900 divisor: "1"  901 - name: POD_NAMESPACE  902 valueFrom:  903 fieldRef:  904 fieldPath: metadata.namespace  905 - name: POD_SERVICE_ACCOUNT  906 valueFrom:  907 fieldRef:  908 fieldPath: spec.serviceAccountName  909 - name: LEADER_ELECTION  910 value: "true"  911 - name: "TLS_SERVER_SECRET_NAME"  912 value: crossplane-tls-server  913 - name: "TLS_SERVER_CERTS_DIR"  914 value: /tls/server  915 - name: "TLS_CLIENT_SECRET_NAME"  916 value: crossplane-tls-client  917 - name: "TLS_CLIENT_CERTS_DIR"  918 value: /tls/client  919 volumeMounts:  920 - mountPath: /cache  921 name: package-cache  922 - mountPath: /tls/server  923 name: tls-server-certs  924 - mountPath: /tls/client  925 name: tls-client-certs  926 volumes:  927 - name: package-cache  928 emptyDir:  929 medium:  930 sizeLimit: 20Mi  931 - name: tls-server-certs  932 secret:  933 secretName: crossplane-tls-server  934 - name: tls-client-certs  935 secret:  936 secretName: crossplane-tls-client  937---  938# Source: crossplane/templates/rbac-manager-deployment.yaml  939apiVersion: apps/v1  940kind: Deployment  941metadata:  942 name: crossplane-rbac-manager  943 namespace: default  944 labels:  945 app: crossplane-rbac-manager  946 release: crossplane  947 helm.sh/chart: crossplane-1.15.0  948 app.kubernetes.io/managed-by: Helm  949 app.kubernetes.io/component: cloud-infrastructure-controller  950 app.kubernetes.io/part-of: crossplane  951 app.kubernetes.io/name: crossplane  952 app.kubernetes.io/instance: crossplane  953 app.kubernetes.io/version: "1.15.0"  954spec:  955 replicas: 1  956 selector:  957 matchLabels:  958 app: crossplane-rbac-manager  959 release: crossplane  960 strategy:  961 type: RollingUpdate  962 template:  963 metadata:  964 labels:  965 app: crossplane-rbac-manager  966 release: crossplane  967 helm.sh/chart: crossplane-1.15.0  968 app.kubernetes.io/managed-by: Helm  969 app.kubernetes.io/component: cloud-infrastructure-controller  970 app.kubernetes.io/part-of: crossplane  971 app.kubernetes.io/name: crossplane  972 app.kubernetes.io/instance: crossplane  973 app.kubernetes.io/version: "1.15.0"  974 spec:  975 serviceAccountName: rbac-manager  976 initContainers:  977 - image: "xpkg.crossplane.io/crossplane/crossplane:v1.15.0"  978 args:  979 - rbac  980 - init  981 imagePullPolicy: IfNotPresent  982 name: crossplane-init  983 resources:  984 limits:  985 cpu: 100m  986 memory: 512Mi  987 requests:  988 cpu: 100m  989 memory: 256Mi  990 securityContext:  991 allowPrivilegeEscalation: false  992 readOnlyRootFilesystem: true  993 runAsGroup: 65532  994 runAsUser: 65532  995 env:  996 - name: GOMAXPROCS  997 valueFrom:  998 resourceFieldRef:  999 containerName: crossplane-init 1000 resource: limits.cpu 1001 - name: GOMEMLIMIT 1002 valueFrom: 1003 resourceFieldRef: 1004 containerName: crossplane-init 1005 resource: limits.memory 1006 containers: 1007 - image: "xpkg.crossplane.io/crossplane/crossplane:v1.15.0" 1008 args: 1009 - rbac 1010 - start 1011 - --provider-clusterrole=crossplane:allowed-provider-permissions 1012 imagePullPolicy: IfNotPresent 1013 name: crossplane 1014 resources: 1015 limits: 1016 cpu: 100m 1017 memory: 512Mi 1018 requests: 1019 cpu: 100m 1020 memory: 256Mi 1021 securityContext: 1022 allowPrivilegeEscalation: false 1023 readOnlyRootFilesystem: true 1024 runAsGroup: 65532 1025 runAsUser: 65532 1026 env: 1027 - name: GOMAXPROCS 1028 valueFrom: 1029 resourceFieldRef: 1030 containerName: crossplane 1031 resource: limits.cpu 1032 - name: GOMEMLIMIT 1033 valueFrom: 1034 resourceFieldRef: 1035 containerName: crossplane 1036 resource: limits.memory 1037 - name: LEADER_ELECTION 1038 value: "true" 1039 1040NOTES: 1041Release: crossplane 1042 1043Chart Name: crossplane 1044Chart Description: Crossplane is an open source Kubernetes add-on that enables platform teams to assemble infrastructure from multiple vendors, and expose higher level self-service APIs for application teams to consume. 1045Chart Version: 1.15.0 1046Chart Application Version: 1.15.0 1047 1048Kube Version: v1.27.3 

Install the Crossplane components using helm install.

1helm install crossplane \ 2crossplane-stable/crossplane \ 3--namespace crossplane-system \ 4--create-namespace 

Verify Crossplane installed with kubectl get pods.

1kubectl get pods -n crossplane-system 2NAME READY STATUS RESTARTS AGE 3crossplane-d4cd8d784-ldcgb 1/1 Running 0 54s 4crossplane-rbac-manager-84769b574-6mw6f 1/1 Running 0 54s 

Installing Crossplane creates new Kubernetes API end-points. Look at the new API end-points with kubectl api-resources | grep crossplane.

 1kubectl api-resources | grep crossplane  2compositeresourcedefinitions xrd,xrds apiextensions.crossplane.io/v1 false CompositeResourceDefinition  3compositionrevisions comprev apiextensions.crossplane.io/v1 false CompositionRevision  4compositions comp apiextensions.crossplane.io/v1 false Composition  5environmentconfigs envcfg apiextensions.crossplane.io/v1beta1 false EnvironmentConfig  6usages apiextensions.crossplane.io/v1alpha1 false Usage  7configurationrevisions pkg.crossplane.io/v1 false ConfigurationRevision  8configurations pkg.crossplane.io/v1 false Configuration  9controllerconfigs pkg.crossplane.io/v1alpha1 false ControllerConfig 10deploymentruntimeconfigs pkg.crossplane.io/v1beta1 false DeploymentRuntimeConfig 11functionrevisions pkg.crossplane.io/v1beta1 false FunctionRevision 12functions pkg.crossplane.io/v1beta1 false Function 13locks pkg.crossplane.io/v1beta1 false Lock 14providerrevisions pkg.crossplane.io/v1 false ProviderRevision 15providers pkg.crossplane.io/v1 false Provider 16storeconfigs secrets.crossplane.io/v1alpha1 false StoreConfig 

Install the AWS provider

Install the AWS S3 provider into the Kubernetes cluster with a Kubernetes configuration file.

1cat <<EOF | kubectl apply -f - 2apiVersion: pkg.crossplane.io/v1 3kind: Provider 4metadata: 5 name: provider-aws-s3 6spec: 7 package: xpkg.crossplane.io/crossplane-contrib/provider-aws-s3:v1.21.1 8EOF 

The Crossplane Provider installs the Kubernetes Custom Resource Definitions (CRDs) representing AWS S3 services. These CRDs allow you to create AWS resources directly inside Kubernetes.

Verify the provider installed with kubectl get providers.

1kubectl get providers 2NAME INSTALLED HEALTHY PACKAGE AGE 3crossplane-contrib-provider-family-aws True True xpkg.crossplane.io/crossplane-contrib/provider-family-aws:v1.21.1 30s 4provider-aws-s3 True True xpkg.crossplane.io/crossplane-contrib/provider-aws-s3:v1.21.1 34s 

The S3 Provider installs a second Provider, the crossplane-contrib-provider-family-aws.
The family provider manages authentication to AWS across all AWS family Providers.

You can view the new CRDs with kubectl get crds.
Every CRD maps to a unique AWS service Crossplane can provision and manage.

Tip
See details about all the supported CRDs in the provider examples.

Create a Kubernetes secret for AWS

The provider requires credentials to create and manage AWS resources.
Providers use a Kubernetes Secret to connect the credentials to the provider.

Generate a Kubernetes Secret from your AWS key-pair and then configure the Provider to use it.

Generate an AWS key-pair file

For basic user authentication, use an AWS Access keys key-pair file.

Tip
The AWS documentation provides information on how to generate AWS Access keys.

Create a text file containing the AWS account aws_access_key_id and aws_secret_access_key.

1[default] 2aws_access_key_id =  3aws_secret_access_key =  

Save this text file as aws-credentials.txt.

Tip
The Authentication section of the AWS Provider documentation describes other authentication methods.

Create a Kubernetes secret with the AWS credentials

A Kubernetes generic secret has a name and contents.
Use kubectl create secret
to generate the secret object named aws-secret
in the crossplane-system namespace.

Use the --from-file= argument to set the value to the contents of the aws-credentials.txt file.

1kubectl create secret \ 2generic aws-secret \ 3-n crossplane-system \ 4--from-file=creds=./aws-credentials.txt 

View the secret with kubectl describe secret

Tip
The size may be larger if there are extra blank spaces in your text file.
 1kubectl describe secret aws-secret -n crossplane-system  2Name: aws-secret  3Namespace: crossplane-system  4Labels: <none>  5Annotations: <none>  6  7Type: Opaque  8  9Data 10==== 11creds: 114 bytes 

Create a ProviderConfig

A ProviderConfig customizes the settings of the AWS Provider.

Apply the ProviderConfig with the this Kubernetes configuration file:

 1cat <<EOF | kubectl apply -f -  2apiVersion: aws.upbound.io/v1beta1  3kind: ProviderConfig  4metadata:  5 name: default  6spec:  7 credentials:  8 source: Secret  9 secretRef: 10 namespace: crossplane-system 11 name: aws-secret 12 key: creds 13EOF 

This attaches the AWS credentials, saved as a Kubernetes secret, as a secretRef.

The spec.credentials.secretRef.name value is the name of the Kubernetes secret containing the AWS credentials in the spec.credentials.secretRef.namespace.

Create a managed resource

A managed resource is anything Crossplane creates and manages outside of the Kubernetes cluster.

This guide creates an AWS S3 bucket with Crossplane.

The S3 bucket is a managed resource.

Tip
AWS S3 bucket names must be globally unique. To generate a unique name the example uses a random hash. Any unique name is acceptable.
 1cat <<EOF | kubectl create -f -  2apiVersion: s3.aws.upbound.io/v1beta1  3kind: Bucket  4metadata:  5 generateName: crossplane-bucket-  6spec:  7 forProvider:  8 region: us-east-2  9 providerConfigRef: 10 name: default 11EOF 

The apiVersion and kind are from the provider’s CRDs.

The metadata.generateName value is the name of the created S3 bucket in AWS.
This example uses the generated name crossplane-bucket-<hash> in the $bucket variable.

The spec.forProvider.region tells AWS which AWS region to use when deploying resources.

The region can be any AWS Regional endpoint code.

Use kubectl get buckets to verify Crossplane created the bucket.

Tip
Crossplane created the bucket when the values READY and SYNCED are True.
This may take up to 5 minutes.
1kubectl get buckets 2NAME READY SYNCED EXTERNAL-NAME AGE 3crossplane-bucket-hhdzh True True crossplane-bucket-hhdzh 5s 

Delete the managed resource

Before shutting down your Kubernetes cluster, delete the S3 bucket just created.

Use kubectl delete bucket <bucketname> to remove the bucket.

1kubectl delete bucket crossplane-bucket-hhdzh 2bucket.s3.aws.upbound.io "crossplane-bucket-hhdzh" deleted 

Next steps