Azurerator is a Kubernetes cluster operator for automated registration and lifecycle management of Azure Active Directory applications.
This specific implementation is tailored towards managing Azure AD applications within a single tenant for use in Web APIs, i.e. both application and user authentication and authorization.
For NAIS end-users
See https://doc.nais.io/security/auth/azure-ad
The operator introduces a new Kind AzureAdApplication
(shortname azureapp
), and acts upon changes to resources of
this kind.
See the spec in liberator for details.
An example resource is available in config/samples/azureadapplication.yaml.
See lifecycle for details.
make install
You will need the credentials for an Azure AD application with the following Application API permissions for Microsoft Graph:
Application.ReadWrite.All
orApplication.ReadWrite.Owned
- If you use
Application.ReadWrite.Owned
, Azurerator will only be able to manage applications and service principals that it has created. It will no longer be able to process these resources if removed as an owner, unless theApplication.ReadWrite.All
permission is granted.
- If you use
DelegatedPermissionGrant.ReadWrite.All
GroupMember.Read.All
(optional, only needed for the groups-assignment feature)Policy.Read.All
(optional, only needed for the claims-mapping policies feature)CustomSecAttributeAssignment.ReadWrite.All
(optional, only needed for the custom security attributes feature)
Finally, in order to ensure that Azurerator may pre-approve delegated API permissions for the managed applications,
you will need to find and configure the azure.permissiongrant-resource-id
configuration flag.
This ID is the Object ID of an Azure AD Enterprise Application that is unique to each tenant.
You will find this under either the name of GraphAggregatorService
or Microsoft Graph
.
Look for an Enterprise Application that has an Application ID equal to 00000003-0000-0000-c000-000000000000
.
Azurerator can be configured using either command-line flags or equivalent environment variables (i.e. -
, .
-> _
and uppercase), with AZURERATOR_
as prefix. E.g.:
azure.auth.client-id -> AZURERATOR_AZURE_AUTH_CLIENT_ID
The following flags are available:
--azure.auth.client-id string Client ID for Azure AD authentication
--azure.auth.client-secret string Client secret for Azure AD authentication
--azure.delay.between-modifications duration Delay between modification operations to the Graph API. (default 3s)
--azure.features.app-role-assignment-required.enabled Enable 'appRoleAssignmentRequired' for service principals.
--azure.features.claims-mapping-policies.id string Claims-mapping policy ID for custom claims mapping
--azure.features.claims-mapping-policies.enabled Assign custom claims-mapping policies to a service principal
--azure.features.custom-security-attributes.enabled Set custom security attributes on service principals (attribute set of 'Applications':'ManagedBy':'NAIS')
--azure.features.cleanup-orphans.enabled Enable cleanup of orphaned resources.
--azure.features.group-membership-claim.default string Default group membership claim for Azure AD apps. (default "ApplicationGroup")
--azure.features.groups-assignment.all-users-group-id string Group ID that contains all users in the tenant. Assigned to all application by default unless overridden by user in the custom resource.
--azure.features.groups-assignment.enabled Assign groups to applications
--azure.pagination.max-pages int Max number of pages to fetch when fetching paginated resources from the Graph API. (default 1000)
--azure.permissiongrant-resource-id string Object ID for Graph API permissions grant ('GraphAggregatorService' or 'Microsoft Graph' in Enterprise Applications under 'Microsoft Applications')
--azure.tenant.id string Tenant ID for Azure AD
--azure.tenant.name string Alias/name of tenant for Azure AD
--cluster-name string The cluster in which this application should run
--controller.context-timeout duration Context timeout for the reconciliation loop in the controller. (default 5m0s)
--kafka.brokers strings Comma-separated list of Kafka brokers, HOST:PORT. (default [localhost:9092])
--kafka.enabled Toggle for enabling Kafka to allow synchronization of events between Azurerator instances.
--kafka.max-processing-time duration Maximum processing time of Kafka messages. (default 10s)
--kafka.retry-interval duration Retry interval for Kafka operations. (default 5s)
--kafka.tls.ca-path string Path to Kafka TLS CA certificate.
--kafka.tls.certificate-path string Path to Kafka TLS certificate.
--kafka.tls.enabled Use TLS for connecting to Kafka.
--kafka.tls.private-key-path string Path to Kafka TLS private key.
--kafka.topic string Name of the Kafka topic that Azurerator should use. (default "azurerator-events")
--leader-election.enabled Leader election toggle.
--leader-election.namespace string Leader election namespace.
--metrics-address string The address the metric endpoint binds to. (default ":8080")
--secret-rotation.cleanup Clean up unused credentials in Azure AD after rotation. (default true)
--secret-rotation.max-age duration Maximum duration since last rotation before triggering rotation on next reconciliation, regardless of secret name being changed. (default 2880h0m0s)
--validations.tenant.required If true, will only process resources that have a tenant defined in the spec
At minimum, the following configuration should be provided:
azure.auth.client-id
azure.auth.client-secret
azure.permissiongrant-resource-id
azure.tenant.id
azure.tenant.name
cluster-name
Equivalently, one can specify these properties using JSON, TOML, YAML, HCL, envfile and Java properties config files.
Azurerator looks for a file named azurerator.<ext>
in the directories [.
, /etc/azurerator/
].
Example configuration in YAML:
# ./azurerator.yaml
azure:
auth:
client-id: ""
client-secret: ""
tenant:
id: ""
name: "local.test" # e.g. your domain
permissiongrant-resource-id: ""
cluster-name: minikube
After configuration, assuming you have a Kubernetes cluster running locally (e.g. using minikube):
ulimit -n 4096 # for controller-gen
make run # starts the controller
# in another terminal, apply an AzureAdApplication resource
make sample
Kubebuilder is required for running the tests. Install with make kubebuilder
.
The image is signed "keylessly" (is that a word?) using Sigstore cosign. To verify its authenticity run
cosign verify \
--certificate-identity "https://github.com/nais/azurerator/.github/workflows/main.yml@refs/heads/master" \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
ghcr.io/nais/azurerator@sha256:<shasum>
The images are also attested with SBOMs in the CycloneDX format. You can verify these by running
cosign verify-attestation --type cyclonedx \
--certificate-identity "https://github.com/nais/azurerator/.github/workflows/main.yml@refs/heads/master" \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
ghcr.io/nais/azurerator@sha256:<shasum>