diff --git a/1. Crossplane Composition Functions/README.md b/1. Crossplane Composition Functions/README.md new file mode 100644 index 0000000..e69de29 diff --git a/1. Crossplane Composition Functions/providers/azure-providers.yml b/1. Crossplane Composition Functions/providers/azure-providers.yml new file mode 100644 index 0000000..707de62 --- /dev/null +++ b/1. Crossplane Composition Functions/providers/azure-providers.yml @@ -0,0 +1,38 @@ +apiVersion: pkg.crossplane.io/v1 +kind: Provider +metadata: + name: provider-family-azure +spec: + package: xpkg.upbound.io/upbound/provider-family-azure:v1.11.0 + runtimeConfigRef: + name: workload-identity-config +--- +apiVersion: pkg.crossplane.io/v1 +kind: Provider +metadata: + name: provider-azure-managedidentity +spec: + package: xpkg.upbound.io/upbound/provider-azure-managedidentity:v1.11.0 + skipDependencyResolution: true + runtimeConfigRef: + name: workload-identity-config +--- +apiVersion: pkg.crossplane.io/v1 +kind: Provider +metadata: + name: provider-azure-authorization +spec: + package: xpkg.upbound.io/upbound/provider-azure-authorization:v1.11.0 + skipDependencyResolution: true + runtimeConfigRef: + name: workload-identity-config +--- +apiVersion: pkg.crossplane.io/v1 +kind: Provider +metadata: + name: provider-azure-storage +spec: + package: xpkg.upbound.io/upbound/provider-azure-storage:v1.11.0 + skipDependencyResolution: true + runtimeConfigRef: + name: workload-identity-config \ No newline at end of file diff --git a/1. Crossplane Composition Functions/providers/workload-identity.yml b/1. Crossplane Composition Functions/providers/workload-identity.yml new file mode 100644 index 0000000..117ed23 --- /dev/null +++ b/1. Crossplane Composition Functions/providers/workload-identity.yml @@ -0,0 +1,28 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + annotations: + azure.workload.identity/client-id: client-id + azure.workload.identity/tenant-id: tenant-id + name: workload-identity-crossplane + namespace: crossplane-system +--- +apiVersion: pkg.crossplane.io/v1beta1 +kind: DeploymentRuntimeConfig +metadata: + name: workload-identity-config + namespace: crossplane-system +spec: + deploymentTemplate: + spec: + selector: {} + template: + metadata: + labels: + azure.workload.identity/use: "true" + spec: + serviceAccountName: workload-identity-crossplane + containers: + - name: package-runtime + args: + - --enable-management-policies \ No newline at end of file diff --git a/1. Crossplane Composition Functions/resources/composition-function.yml b/1. Crossplane Composition Functions/resources/composition-function.yml new file mode 100644 index 0000000..5e2f2a4 --- /dev/null +++ b/1. Crossplane Composition Functions/resources/composition-function.yml @@ -0,0 +1,184 @@ +### XRD ### +apiVersion: apiextensions.crossplane.io/v1 +kind: CompositeResourceDefinition +metadata: + name: azureapps.crossplane.io +spec: + group: crossplane.io + names: + kind: AzureApp + plural: azureapps + claimNames: + kind: AzureAppClaim + plural: azureappclaims + versions: + - name: v1alpha1 + served: true + referenceable: true + schema: + openAPIV3Schema: + type: object + properties: + spec: + type: object + properties: + parameters: + type: object + properties: + resourceGroup: + type: string + subscription: + type: string + tenant: + type: string + managedIdentity: + type: string + storageAccount: + type: string + roles: + type: array + items: + type: string + status: + type: object + properties: + principalId: + type: string +--- +### Composition ### +apiVersion: apiextensions.crossplane.io/v1 +kind: Composition +metadata: + name: example +spec: + compositeTypeRef: + apiVersion: crossplane.io/v1alpha1 + kind: AzureApp + mode: Pipeline # We add this so Crossplane knows we are going to be using Functions + pipeline: + - step: create-resources + functionRef: + name: function-patch-and-transform + input: + apiVersion: pt.fn.crossplane.io/v1beta1 + kind: Resources + resources: + - name: resource-group + base: + apiVersion: azure.upbound.io/v1beta1 + kind: ResourceGroup + metadata: + labels: + testing.upbound.io/example-name: resource-group + spec: + forProvider: + location: West Europe + patches: + - fromFieldPath: "spec.parameters.resourceGroup" + toFieldPath: "spec.forProvider.name" + - name: storage-account + base: + apiVersion: storage.azure.upbound.io/v1beta1 + kind: Account + spec: + forProvider: + accountKind: StorageV2 + accountReplicationType: LRS + accountTier: Standard + isHnsEnabled: true + location: West Europe + resourceGroupNameSelector: + matchLabels: + testing.upbound.io/example-name: resource-group + patches: + - fromFieldPath: "spec.parameters.storageAccount" + toFieldPath: "metadata.name" + - name: managed-identity + base: + apiVersion: managedidentity.azure.upbound.io/v1beta1 + kind: UserAssignedIdentity + metadata: + labels: + testing.upbound.io/example-name: managed-identity + spec: + forProvider: + location: West Europe + resourceGroupNameSelector: + matchLabels: + testing.upbound.io/example-name: resource-group + patches: + - fromFieldPath: "spec.parameters.managedIdentity" + toFieldPath: "spec.forProvider.name" + - type: ToCompositeFieldPath + fromFieldPath: "status.atProvider.principalId" + toFieldPath: "status.principalId" + - name: federated-credential + base: + apiVersion: managedidentity.azure.upbound.io/v1beta1 + kind: FederatedIdentityCredential + spec: + forProvider: + issuer: "https://issuer" + audience: + - "api://AzureADTokenExchange" + subject: "system:serviceaccount:namespace:application" + parentIdSelector: + matchLabels: + testing.upbound.io/example-name: managed-identity + resourceGroupNameSelector: + matchLabels: + testing.upbound.io/example-name: resource-group + patches: + - type: FromCompositeFieldPath + fromFieldPath: "spec.parameters.managedIdentity" + toFieldPath: "metadata.name" + - step: create-role-assignments + functionRef: + name: function-go-templating + input: + apiVersion: gotemplating.fn.crossplane.io/v1beta1 + kind: GoTemplate + source: Inline + inline: + template: | + {{- $subscription := .observed.composite.resource.spec.parameters.subscription -}} + {{- $resourceGroup := .observed.composite.resource.spec.parameters.resourceGroup -}} + {{- $roles := $composite.spec.parameters.roles -}} + {{- $principalId := $composite.status.principalId -}} + {{ range $index, $roleName := $roles }} + --- + apiVersion: authorization.azure.upbound.io/v1beta1 + kind: RoleAssignment + metadata: + name: roleassignment-{{ $index }} + annotations: + gotemplating.fn.crossplane.io/composition-resource-name: roleassignment-{{ $index }} + spec: + forProvider: + name: roleassignment-{{ $index }} + scope: {{ /subscriptions/{{ $subscription }}/resourceGroups/{{ $resourceGroup }}/providers/Microsoft.Storage/storageAccounts/example }} + roleDefinitionName: "{{ $roleName }}" + principalId: "{{ $principalId }}" + providerConfigRef: + name: workload-identity-provider-config + {{- end }} +--- +### XR ### +apiVersion: crossplane.io +kind: AzureApp +metadata: + name: example +spec: + compositionRef: + name: azure-apps + parameters: + resourceGroup: resource-group + subscription: 12345678-aaaa-bbbb-cccc-123456789012 + managedIdentity: managed-identity + storageAccount: example + roles: + - Reader + - Contributor + - Storage Blob Data Reader + - Storage Table Data Contributor + - Role Based Access Control Administrator \ No newline at end of file diff --git a/1. Crossplane Composition Functions/resources/composition.yml b/1. Crossplane Composition Functions/resources/composition.yml new file mode 100644 index 0000000..2427403 --- /dev/null +++ b/1. Crossplane Composition Functions/resources/composition.yml @@ -0,0 +1,162 @@ +### XRD ### +apiVersion: apiextensions.crossplane.io/v1 +kind: CompositeResourceDefinition +metadata: + name: azureapps.crossplane.io +spec: + group: crossplane.io + names: + kind: AzureApp + plural: azureapps + claimNames: + kind: AzureAppClaim + plural: azureappclaims + versions: + - name: v1alpha1 + served: true + referenceable: true + schema: + openAPIV3Schema: + type: object + properties: + spec: + type: object + properties: + parameters: + type: object + properties: + resourceGroup: + type: string + subscription: + type: string + tenant: + type: string + managedIdentity: + type: string + storageAccount: + type: string + role: + type: string + status: + type: object + properties: + principalId: + type: string +--- +### Composition ### +apiVersion: apiextensions.crossplane.io/v1 +kind: Composition +metadata: + name: example +spec: + compositeTypeRef: + apiVersion: crossplane.io/v1alpha1 + kind: AzureApp + resources: + - name: resource-group + base: + apiVersion: azure.upbound.io/v1beta1 + kind: ResourceGroup + metadata: + labels: + testing.upbound.io/example-name: resource-group + spec: + forProvider: + location: West Europe + patches: + - fromFieldPath: "spec.parameters.resourceGroup" + toFieldPath: "spec.forProvider.name" + - name: storage-account + base: + apiVersion: storage.azure.upbound.io/v1beta1 + kind: Account + spec: + forProvider: + accountKind: StorageV2 + accountReplicationType: LRS + accountTier: Standard + isHnsEnabled: true + location: West Europe + resourceGroupNameSelector: + matchLabels: + testing.upbound.io/example-name: resource-group + patches: + - fromFieldPath: "spec.parameters.storageAccount" + toFieldPath: "metadata.name" + - name: managed-identity + base: + apiVersion: managedidentity.azure.upbound.io/v1beta1 + kind: UserAssignedIdentity + metadata: + labels: + testing.upbound.io/example-name: managed-identity + spec: + forProvider: + location: West Europe + resourceGroupNameSelector: + matchLabels: + testing.upbound.io/example-name: resource-group + patches: + - fromFieldPath: "spec.parameters.managedIdentity" + toFieldPath: "spec.forProvider.name" + - type: ToCompositeFieldPath + fromFieldPath: "status.atProvider.principalId" + toFieldPath: "status.principalId" + - name: federated-credential + base: + apiVersion: managedidentity.azure.upbound.io/v1beta1 + kind: FederatedIdentityCredential + spec: + forProvider: + issuer: "https://issuer" + audience: + - "api://AzureADTokenExchange" + subject: "system:serviceaccount:namespace:application" + parentIdSelector: + matchLabels: + testing.upbound.io/example-name: managed-identity + resourceGroupNameSelector: + matchLabels: + testing.upbound.io/example-name: resource-group + patches: + - type: FromCompositeFieldPath + fromFieldPath: "spec.parameters.managedIdentity" + toFieldPath: "metadata.name" + - name: role-assignment + base: + apiVersion: authorization.azure.upbound.io/v1beta1 + kind: RoleAssignment + spec: + forProvider: + principalId: "" # this was previously unknown, but now it is patched in from the status.principalId field in the Composite Resource + roleDefinitionName: Reader + scope: "/subscriptions//resourceGroups//providers/Microsoft.Storage/storageAccounts/example" + patches: + - fromFieldPath: "status.principalId" + toFieldPath: "spec.forProvider.principalId" + - fromFieldPath: "spec.parameters.role" + toFieldPath: "spec.forProvider.roleDefinitionName" + - type: CombineFromComposite + combine: + variables: + - fromFieldPath: "spec.parameters.subscription" + - fromFieldPath: "spec.parameters.resourceGroup" + - fromFieldPath: "spec.parameters.storageAccount" + strategy: string + string: + fmt: "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Storage/storageAccounts/%s" +--- +### XR ### +apiVersion: crossplane.io +kind: AzureApp +metadata: + name: example +spec: + compositionRef: + name: azure-apps + parameters: + resourceGroup: resource-group + subscription: 12345678-aaaa-bbbb-cccc-123456789012 + managedIdentity: managed-identity + storageAccount: example + role: Reader \ No newline at end of file diff --git a/1. Crossplane Composition Functions/resources/functions.yml b/1. Crossplane Composition Functions/resources/functions.yml new file mode 100644 index 0000000..6e2716c --- /dev/null +++ b/1. Crossplane Composition Functions/resources/functions.yml @@ -0,0 +1,17 @@ +apiVersion: pkg.crossplane.io/v1 +kind: Function +metadata: + name: function-patch-and-transform +spec: + package: xpkg.upbound.io/crossplane-contrib/function-patch-and-transform:v0.8.0 + runtimeConfigRef: + name: functions-config +--- +apiVersion: pkg.crossplane.io/v1 +kind: Function +metadata: + name: function-go-templating +spec: + package: xpkg.upbound.io/crossplane-contrib/function-go-templating:v0.9.0 + runtimeConfigRef: + name: functions-config \ No newline at end of file diff --git a/1. Crossplane Composition Functions/resources/resources.yml b/1. Crossplane Composition Functions/resources/resources.yml new file mode 100644 index 0000000..85ab91f --- /dev/null +++ b/1. Crossplane Composition Functions/resources/resources.yml @@ -0,0 +1,67 @@ +apiVersion: azure.upbound.io/v1beta1 +kind: ResourceGroup +metadata: + name: resource-group + labels: + testing.upbound.io/example-name: resource-group +spec: + forProvider: + location: West Europe + tags: + provisioner: crossplane +--- +apiVersion: storage.azure.upbound.io/v1beta1 +kind: Account +metadata: + name: storage-account +spec: + forProvider: + accountKind: StorageV2 + accountReplicationType: LRS + accountTier: Standard + isHnsEnabled: true + location: West Europe + resourceGroupNameSelector: + matchLabels: + testing.upbound.io/example-name: resource-group +--- +apiVersion: authorization.azure.upbound.io/v1beta1 +kind: RoleAssignment +metadata: + name: role-assignment +spec: + forProvider: + principalId: principal_id # this is unknown + roleDefinitionName: Reader + scope: "/subscriptions//resourceGroups//providers/Microsoft.Storage/storageAccounts/example" +--- +apiVersion: managedidentity.azure.upbound.io/v1beta1 +kind: UserAssignedIdentity +metadata: + name: managed-identity + labels: + testing.upbound.io/example-name: managed-identity +spec: + forProvider: + location: West Europe + name: exmplemanagidentity + resourceGroupNameSelector: + matchLabels: + testing.upbound.io/example-name: managidentity-rg +--- +apiVersion: managedidentity.azure.upbound.io/v1beta1 +kind: FederatedIdentityCredential +metadata: + name: federated-credential +spec: + forProvider: + audience: + - "api://AzureADTokenExchange" + issuer: https://issuer + parentIdSelector: + matchLabels: + testing.upbound.io/example-name: managed-identity + resourceGroupNameSelector: + matchLabels: + testing.upbound.io/example-name: resource-group + subject: system:serviceaccount:namespace:application \ No newline at end of file