Crossplane logo
Crossplane logo
  • Why Control Planes?
  • Documentation
  • Community
  • Blog
  • Crossplane GitHub
  • Crossplane Slack
Crossplane Documentation - v1.19
Overview
Getting Started
Crossplane Introduction
AWS Quickstart
Azure Quickstart
GCP Quickstart
Install, Upgrade and Uninstall
Install Crossplane
Upgrade Crossplane
Uninstall Crossplane
Concepts
Crossplane Pods
Providers
Managed Resources
Compositions
Composition Revisions
Composite Resource Definitions
Composite Resources
Claims
Environment Configurations
Usages
Connection Details
Configuration Packages
Server-Side Apply
Image Configs
Guides
Disaster Recovery with Crossplane
Metrics
Function Patch and Transform
Releasing Crossplane Extensions
Write a Composition Function in Go
Write a Composition Function in Python
Import Existing Resources
Vault as an External Secret Store
Vault Credential Injection
Multi-Tenant Crossplane
Configuring Crossplane with Argo CD
Self-Signed CA Certs
Troubleshoot Crossplane
CLI Reference
Command Reference
API Reference
Learn More
Release Cycle
Feature Lifecycle
Contributing Guide
Crossplane Roadmap
v1.19
master v2.0-preview v2.0
Latest
v1.20 v1.19

Azure Quickstart

On this page
  • Prerequisites
  • Install the Azure provider
  • Create a Kubernetes secret for Azure
    • Install the Azure command-line
    • Create an Azure service principal
    • Create a Kubernetes secret with the Azure credentials
  • Create a ProviderConfig
  • Create a managed resource
  • Delete the managed resource
  • Next steps
Report a problem
View page source
This document is for an older version of Crossplane.

This document applies to Crossplane v1.19 and not to the latest release v2.0.

Connect Crossplane to Azure to create and manage cloud resources from Kubernetes with
provider-upjet-azure.

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:

  • 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 Azure account with permissions to create an Azure Virtual Machine and Virtual Network
  • an Azure account with permissions to create an Azure service principal and an Azure resource group

Install Crossplane

Crossplane installs into an existing Kubernetes cluster.

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

Install the Crossplane Helm chart

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

Enable the Crossplane Helm Chart repository:

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

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

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

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

Install the Crossplane components using helm install.

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

Verify Crossplane installed with kubectl get pods.

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

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

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

Install the 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.crossplane.io/crossplane-contrib/provider-azure-network:v1.11.2 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 3crossplane-contrib-provider-family-azure   True        True      xpkg.crossplane.io/crossplane-contrib/provider-family-azure:v1.11.2    2m18s 4provider-azure-network                     True        True      xpkg.crossplane.io/crossplane-contrib/provider-azure-network:v1.11.2   2m23s 

The Network Provider installs a second Provider, the crossplane-contrib-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 provider examples.

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

  • Continue to part 2 to create and use a custom API with Crossplane.
  • Explore Azure resources that Crossplane can configure in the Provider CRD reference.
  • Join the Crossplane Slack and connect with Crossplane users and contributors.
Crossplane logo
Twitter
Youtube
Podcast
Forum

© Crossplane Authors 2025. Documentation distributed under CC-BY-4.0.

© 2025 The Linux Foundation. All rights reserved. The Linux Foundation has registered trademarks and uses trademarks. For a list of trademarks of The Linux Foundation, please see our Trademark Usage page.

cncfLogo

We are a Cloud Native Computing Foundation incubating project.