Connect Crossplane to AWS to create and manage cloud resources from Kubernetes with the Upbound AWS Provider.

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.upbound.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.upbound.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.upbound.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.upbound.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.upbound.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.upbound.io/upbound/provider-aws-s3:v1.17.0
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
3provider-aws-s3               True        True      xpkg.upbound.io/upbound/provider-aws-s3:1.1.0         97s
4upbound-provider-family-aws   True        True      xpkg.upbound.io/upbound/provider-family-aws:1.1.0     88s

The S3 Provider installs a second Provider, the upbound-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 Upbound Marketplace.

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.name 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