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

This guide is in two parts:

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

Prerequisites

This quickstart requires:

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

Install the Azure Network resource 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-azure-network
6spec:
7  package: xpkg.upbound.io/upbound/provider-azure-network:v0.34.0
8EOF

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

Verify the provider installed with kubectl get providers.

1kubectl get providers
2NAME                            INSTALLED   HEALTHY   PACKAGE                                                  AGE
3provider-azure-network          True        True      xpkg.upbound.io/upbound/provider-azure-network:v0.34.0   38s
4upbound-provider-family-azure   True        True      xpkg.upbound.io/upbound/provider-family-azure:v0.34.0    26s

The Network Provider installs a second Provider, the upbound-provider-family-azure provider.
The family provider manages authentication to Azure across all Azure family Providers.

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

Tip
See details about all the supported CRDs in the Upbound Marketplace.

Create a Kubernetes secret for Azure

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

This guide generates an Azure service principal JSON file and saves it as a Kubernetes Secret.

Install the Azure command-line

Generating an authentication file requires the Azure command-line.
Follow the documentation from Microsoft to Download and install the Azure command-line.

Log in to the Azure command-line.

az login

Create an Azure service principal

Follow the Azure documentation to find your Subscription ID from the Azure Portal.

Using the Azure command-line and provide your Subscription ID create a service principal and authentication file.

1az ad sp create-for-rbac \
2--sdk-auth \
3--role Owner \
4--scopes /subscriptions/

Save your Azure JSON output as azure-credentials.json.

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

Create a Kubernetes secret with the Azure credentials

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

Use the --from-file= argument to set the value to the contents of the azure-credentials.json file.

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

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 azure-secret -n crossplane-system
 2Name:         azure-secret
 3Namespace:    crossplane-system
 4Labels:       <none>
 5Annotations:  <none>
 6
 7Type:  Opaque
 8
 9Data
10====
11creds:  629 bytes

Create a ProviderConfig

A ProviderConfig customizes the settings of the Azure Provider.

Apply the ProviderConfig with the command:

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

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

The spec.credentials.secretRef.name value is the name of the Kubernetes secret containing the Azure 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 example creates an Azure Virtual Network with Crossplane. The Virtual Network is a managed resource.

Tip
Add your Azure Resource Group name. Follow the Azure documentation to create a resource group if you don’t have one.
 1cat <<EOF | kubectl create -f -
 2apiVersion: network.azure.upbound.io/v1beta1
 3kind: VirtualNetwork
 4metadata:
 5  name: crossplane-quickstart-network
 6spec:
 7  forProvider:
 8    addressSpace:
 9      - 10.0.0.0/16
10    location: "Sweden Central"
11    resourceGroupName: docs
12EOF

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

The spec.forProvider.location tells Azure which location to use when deploying the resource.

Use kubectl get virtualnetwork.network to verify Crossplane created the Azure Virtual Network.

Tip
Crossplane created the virtual network when the values READY and SYNCED are True.
This may take up to 5 minutes.
1kubectl get virtualnetwork.network
2NAME                            READY   SYNCED   EXTERNAL-NAME                   AGE
3crossplane-quickstart-network   True    True     crossplane-quickstart-network   10m

Delete the managed resource

Before shutting down your Kubernetes cluster, delete the virtual network just created.

Use kubectl delete virtualnetwork.network to delete the virtual network.

1kubectl delete virtualnetwork.network crossplane-quickstart-network
2virtualnetwork.network.azure.upbound.io "crossplane-quickstart-network" deleted

Next steps