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

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/v1alpha1   false        EnvironmentConfig
 6configurationrevisions                         pkg.crossplane.io/v1                   false        ConfigurationRevision
 7configurations                                 pkg.crossplane.io/v1                   false        Configuration
 8controllerconfigs                              pkg.crossplane.io/v1alpha1             false        ControllerConfig
 9locks                                          pkg.crossplane.io/v1beta1              false        Lock
10providerrevisions                              pkg.crossplane.io/v1                   false        ProviderRevision
11providers                                      pkg.crossplane.io/v1                   false        Provider
12storeconfigs                                   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:v0.37.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:v0.37.0       2m53s
4upbound-provider-family-aws   True        True      xpkg.upbound.io/upbound/provider-family-aws:v0.37.0   2m48s

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.
 1bucket=$(echo "crossplane-bucket-"$(head -n 4096 /dev/urandom | openssl sha1 | tail -c 10))
 2cat <<EOF | kubectl apply -f -
 3apiVersion: s3.aws.upbound.io/v1beta1
 4kind: Bucket
 5metadata:
 6  name: $bucket
 7spec:
 8  forProvider:
 9    region: us-east-2
10  providerConfigRef:
11    name: default
12EOF

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-45eed4ae0   True    True     crossplane-bucket-45eed4ae0   61s

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 $bucket
2bucket.s3.aws.upbound.io "crossplane-bucket-45eed4ae0" deleted

Next steps