-
Notifications
You must be signed in to change notification settings - Fork 878
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1509 from pulumi/torian/azure-py-oidc-provider-pu…
…lumi-cloud Create Pulumi to Azure OIDC Configuration Example
- Loading branch information
Showing
5 changed files
with
194 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
*.pyc | ||
venv/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
name: oidc-test | ||
runtime: | ||
name: python | ||
options: | ||
virtualenv: venv | ||
description: A Python Pulumi program |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
# Provisioning an OIDC Provider in Azure for Pulumi Cloud | ||
|
||
This example will create OIDC configuration between Pulumi Cloud and Azure, specifically demonstrating connectivity with [Pulumi ESC](https://www.pulumi.com/docs/pulumi-cloud/esc/). The program automates the process detailed in the Azure documentation for the following activities: | ||
|
||
- [Create a Microsoft Entra application and service principal that can access resources](https://learn.microsoft.com/en-us/azure/active-directory/develop/howto-create-service-principal-portal) | ||
- [Create federated credentials](https://azure.github.io/azure-workload-identity/docs/topics/federated-identity-credential.html#federated-identity-credential-for-an-azure-ad-application-1) | ||
|
||
## Prerequisites | ||
|
||
* [Install Pulumi](https://www.pulumi.com/docs/get-started/install/) | ||
* [Configure Pulumi to Use Azure](https://www.pulumi.com/docs/clouds/azure/get-started/begin/) | ||
|
||
## Running the Example | ||
|
||
Clone [the examples repo](https://github.com/pulumi/examples/tree/master/azure-py-oidc-provider) and navigate to the folder for this example. | ||
|
||
```bash | ||
git clone https://github.com/pulumi/examples.git | ||
cd examples/azure-py-oidc-provider-pulumi-cloud | ||
``` | ||
|
||
Next, to deploy the application and its infrastructure, follow these steps: | ||
|
||
1. Create a new stack, which is an isolated deployment target for this example: | ||
|
||
```bash | ||
pulumi stack init dev | ||
``` | ||
|
||
1. Set your Pulumi ESC environment name and desired Azure region: | ||
|
||
```bash | ||
pulumi config set environmentName <your-environment-name> # replace with your environment name | ||
pulumi config set azure-native:location WestUS2 # any valid Azure region will work | ||
``` | ||
|
||
1. Install requirements. | ||
|
||
```bash | ||
python3 -m venv venv | ||
venv/bin/pip install -r requirements.txt | ||
``` | ||
|
||
1. Run `pulumi up -y`. Once the program completes, it will output a YAML template for you to use in the next step. | ||
|
||
## Validating the OIDC Configuration | ||
|
||
This next section will walk you through validating your OIDC configuration using [Pulumi ESC](https://www.pulumi.com/docs/pulumi-cloud/esc/). | ||
|
||
Start by [creating a new Pulumi ESC environment](https://www.pulumi.com/docs/pulumi-cloud/esc/get-started/#create-an-environment). Then, copy the template definition from the output in the CLI and paste it into your environment. Save your environment file and run the `pulumi env open <your-pulumi-org>/<your-environment>` command in the CLI. You should see output similar to the following: | ||
|
||
```bash | ||
$ pulumi env open myOrg/myEnvironment | ||
{ | ||
"azure": { | ||
"login": { | ||
"clientId": "3e5505f6-90b9-....", | ||
"oidc": { | ||
"token": "eyJhbGciOi...." | ||
}, | ||
"subscriptionId": "/subscriptions/0282681f-7a9e....", | ||
"tenantId": "706143bc-e1d4...." | ||
} | ||
} | ||
} | ||
``` | ||
|
||
## Additional Considerations | ||
|
||
You can configure more granular access control by adding a `RoleAssignment` resource to your program. In the following example, the application is assigned a role with permissions to read secrets from Azure Keyvault. | ||
|
||
```python | ||
# Create an IAM role assignment at the subscription level | ||
role_assignment = authorization.RoleAssignment( | ||
'role-assignment', | ||
scope=pulumi.Output.format('/subscriptions/{subscription_id}', subscription_id=az_subscription), | ||
role_definition_id=pulumi.Output.format('/subscriptions/{subscription_id}/providers/Microsoft.Authorization/roleDefinitions/{role_definition_id}', | ||
subscription_id=az_subscription, | ||
role_definition_id='4633458b-17de-408a-b874-0445c86b69e6'), # ID for "Key Vault Secrets User" role | ||
principal_id=application.object_id, | ||
) | ||
``` | ||
|
||
For this example, you would need to update your environment file to retrieve a KeyVault secret: | ||
|
||
```yaml | ||
values: | ||
azure: | ||
login: | ||
fn::open::azure-login: | ||
clientId: <your-client-id> | ||
tenantId: <your-tenant-id> | ||
subscriptionId: /subscriptions/<your-subscription-id> | ||
oidc: true | ||
secrets: | ||
fn::open::azure-secrets: | ||
login: ${azure.login} | ||
vault: <your-vault-name> | ||
get: | ||
api-key: | ||
name: api-key #an example of retrieving a secret named "api-key" and storing it in a parameter | ||
environmentVariables: | ||
API_KEY: ${azure.secrets.api-key} # an example of how you can reference your api-key value elsewhere in the file | ||
``` | ||
|
||
## Clean-Up Resources | ||
|
||
Once you are done, you can destroy all of the resources as well as the stack: | ||
|
||
```bash | ||
$ pulumi destroy | ||
$ pulumi stack rm | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
import pulumi | ||
from pulumi_azure_native import resources, aad, authorization, managedidentity | ||
import pulumi_azuread as azuread | ||
from pulumi_azure import core | ||
import yaml | ||
import random | ||
|
||
number = random.randint(1000,9999) | ||
|
||
issuer = "https://api.pulumi.com/oidc" | ||
|
||
# Retrieve local Pulumi configuration | ||
pulumi_config = pulumi.Config() | ||
audience = pulumi.get_organization() | ||
env_name = pulumi_config.require("environmentName") | ||
|
||
# Retrieve local Azure configuration | ||
azure_config = authorization.get_client_config() | ||
az_subscription = azure_config.subscription_id | ||
tenant_id = azure_config.tenant_id | ||
|
||
# Create an Azure Resource Group (if necessary) | ||
resource_group = resources.ResourceGroup(f'resourceGroup-{number}') | ||
|
||
# Create an Azure AD Application | ||
application = azuread.Application( | ||
f'pulumi-oidc-app-reg-{number}', | ||
display_name='pulumi-environments-oidc-app', | ||
sign_in_audience='AzureADMyOrg', | ||
) | ||
|
||
# Creates Federated Credentials | ||
federated_identity_credential = azuread.ApplicationFederatedIdentityCredential("federatedIdentityCredential", | ||
application_object_id=application.object_id, | ||
display_name=f"pulumi-env-oidc-fic-{number}", | ||
description="Federated credentials for Pulumi ESC", | ||
audiences=[audience], | ||
issuer=issuer, | ||
subject=f"pulumi:environments:org:{audience}:env:{env_name}" | ||
) | ||
|
||
print("OIDC configuration complete!") | ||
print("Copy and paste the following template into your Pulumi ESC environment:") | ||
print("--------") | ||
|
||
def create_yaml_structure(args): | ||
application_id, tenant_id, subscription_id = args | ||
return { | ||
'values': { | ||
'azure': { | ||
'login': { | ||
'fn::open::azure-login': { | ||
'clientId': application_id, | ||
'tenantId': tenant_id, | ||
'subscriptionId': f"/subscriptions/{subscription_id}", | ||
'oidc': True | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
def print_yaml(args): | ||
yaml_structure = create_yaml_structure(args) | ||
yaml_string = yaml.dump(yaml_structure, sort_keys=False) | ||
print(yaml_string) | ||
|
||
pulumi.Output.all(application.application_id, tenant_id, az_subscription).apply(print_yaml) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
pulumi>=3.0.0,<4.0.0 | ||
pulumi-azure-native>=2.0.0,<3.0.0 | ||
pulumi-azuread>=5.0.0, <6.0.0 | ||
pulumi-azure>=5.0.0, <6.0.0 | ||
PyYAML |