Tuesday, October 15, 2019

Azure Dynamic Secret


Configuration to be done on Azure

Steps to generate azure service principle dynamically.

We have to create a root Service Principal on AZ which will be used by Vault for all the abstraction/brokering service

⇒  az login

Create a Service Principal to be used by Vault

Let's create a root service principal with role=Owner which will be used by vault.
For the below command, you will need the subscription ID
- to find subscription id, on your AZ portal, search for subscription and launch the page from the list.
- more details on the command we are running below. ( https://docs.microsoft.com/en-us/cli/azure/ad/sp?view=azure-cli-latest#az-ad-sp-create-for-rbac )

⇒  az ad sp create-for-rbac -n vault-admin-manjeet --role Owner --scope /subscriptions/14692f20-9428-451b-8298-102ed4e39c2a
Changing "vault-admin-manjeet" to a valid URI of "http://vault-admin-manjeet", which is the required format used for service principal names
Creating a role assignment under the scope of "/subscriptions/14692f20-9428-451b-8298-102ed4e39c2a"
  Retrying role assignment creation: 1/36
  Retrying role assignment creation: 2/36
  Retrying role assignment creation: 3/36
{
  "appId": "235e821c-867a-4bc2-93fe-97433d6208b4",
  "displayName": "vault-admin-manjeet",
  "name": "http://vault-admin-manjeet",
  "password": "3d8a8189-a93f-4f0f-a772-410807a76902",
  "tenant": "0e3e2e88-8caf-41ca-b4da-e3b33b6c52ec"
}


- The above output appId can also be verified from both command line and AZ portal

CLI Verification
⇒  az ad sp list --query "[?contains(appId, '235e821c-867a-4bc2-93fe-97433d6208b4')]"

AZ portal - search and launch 'App registration',  then click on 'All applications'. Do another search in this window for the appId output from above. Note, the search works only if you copy/paste the entire appId

Create a custom Role in AZ (optional, but this is to show how you can align the vault role to this same role in AZ)

- Lets check what custom roles are currently in AZ

⇒  az role definition list --custom-role-only true --output json | jq '.[] | {"roleName":.roleName, "roleType":.roleType}'
{
  "roleName": "Vault_ReadOnly",
  "roleType": "CustomRole"
}
{
  "roleName": "vault-test-role",
  "roleType": "CustomRole"
}
{
  "roleName": "HashiCorp Vault Azure Auth",
  "roleType": "CustomRole"
}


- This is the custom role which will be added to AZ portal. Make sure the Name property has something which can be identified easily, I am adding my name to the end
⇒  cat custom-role.json
{
  "Name": "testing-custom-role-manjeet",
  "IsCustom": true,
  "Description": "Testing Vault Azure Secret Engine",
  "Actions": [
    "Microsoft.Storage/*/read",
    "Microsoft.Network/*/read",
    "Microsoft.Compute/*/read",
    "Microsoft.Compute/virtualMachines/start/action",
    "Microsoft.Compute/virtualMachines/restart/action",
    "Microsoft.Authorization/*/read",
    "Microsoft.Resources/subscriptions/resourceGroups/read",
    "Microsoft.Insights/alertRules/*",
    "Microsoft.Support/*"
  ],
  "NotActions": [

  ],
  "AssignableScopes": [
    "/subscriptions/14692f20-9428-451b-8298-102ed4e39c2a"
  ]
}


- Command to create the role using the above json file
⇒  az role definition create --role-definition custom-role.json
{
  "assignableScopes": [
    "/subscriptions/14692f20-9428-451b-8298-102ed4e39c2a"
  ],
  "description": "Testing Vault Azure Secret Engine",
  "id": "/subscriptions/14692f20-9428-451b-8298-102ed4e39c2a/providers/Microsoft.Authorization/roleDefinitions/3f5cab16-188d-4ec0-864b-183d9e4c18ea",
  "name": "3f5cab16-188d-4ec0-864b-183d9e4c18ea",
  "permissions": [
    {
      "actions": [
        "Microsoft.Storage/*/read",
        "Microsoft.Network/*/read",
        "Microsoft.Compute/*/read",
        "Microsoft.Compute/virtualMachines/start/action",
        "Microsoft.Compute/virtualMachines/restart/action",
        "Microsoft.Authorization/*/read",
        "Microsoft.Resources/subscriptions/resourceGroups/read",
        "Microsoft.Insights/alertRules/*",
        "Microsoft.Support/*"
      ],
      "dataActions": [],
      "notActions": [],
      "notDataActions": []
    }
  ],
  "roleName": "testing-custom-role-manjeet",
  "roleType": "CustomRole",
  "type": "Microsoft.Authorization/roleDefinitions"
}


- Verify if the role was added by listing the role definitions

⇒  az role definition list --custom-role-only true --output json | jq '.[] | {"roleName":.roleName, "roleType":.roleType}'
{
  "roleName": "Vault_ReadOnly",
  "roleType": "CustomRole"
}
{
  "roleName": "vault-test-role",
  "roleType": "CustomRole"
}
{
  "roleName": "HashiCorp Vault Azure Auth",
  "roleType": "CustomRole"
}
{
  "roleName": "testing-custom-role-manjeet",
  "roleType": "CustomRole"
}


Configuration to be done on Vault

- Set the environment variables VAULT_ADDR & VAULT_ROOT_TOKEN
- VAULT_ADDR=http://127.0.0.1:8200
- VAULT_ROOT_TOKEN=vault-root-token

- Enable Azure Secrets Engines

# vault secrets enable azure

- Configure this az secrets engine. All the information here will come from the last section

# cat az-dynamic-secrets-config.json
{
        azure_roles:
  "subscription_id": "14692f20-9428-451b-8298-102ed4e39c2a",
  "tenant_id": "0e3e2e88-8caf-41ca-b4da-e3b33b6c52ec",
  "client_id": "235e821c-867a-4bc2-93fe-97433d6208b4",
  "client_secret": "3d8a8189-a93f-4f0f-a772-410807a76902",
        "azure_roles":
  "environment": "AzurePublicCloud"
}

# curl --header "X-Vault-Token: $VAULT_ROOT_TOKEN" --request POST --data @az-dynamic-secrets-config.json  $VAULT_ADDR/v1/azure/config

- Read the az config to check if it was added
# vault read azure/config
Key                Value
---                -----
client_id          235e821c-867a-4bc2-93fe-97433d6208b4
environment        AzurePublicCloud
subscription_id    14692f20-9428-451b-8298-102ed4e39c2a
tenant_id          0e3e2e88-8caf-41ca-b4da-e3b33b6c52ec


- Create a role in Vault
- uuid = subscription_id
- Make sure you have a resource group name Website. If not use the one you already have.

# vault write azure/roles/my-role ttl=5m azure_roles=-<<EOF
> [
> {
> "role_name": "Contributer",
> "scope": "/subscriptions/<uuid>/resourceGroups/Website"
> }
> ]
> EOF

- Actual command I ran.

# vault write azure/roles/my-role ttl=5m azure_roles=-<<EOF
[
{
"role_name": "Contributor",
"scope": "/subscriptions/14692f20-9428-451b-8298-102ed4e39c2a/resourceGroups/my-project-resources"
}
]
EOF

Success! Data written to: azure/roles/my-role

# vault list azure/roles
Keys
----
my-role


# vault read azure/roles/my-role
Key                      Value
---                      -----
application_object_id    n/a
azure_roles              [map[role_id:/subscriptions/14692f20-9428-451b-8298-102ed4e39c2a/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c role_name:Contributor scope:/subscriptions/14692f20-9428-451b-8298-102ed4e39c2a/resourceGroups/Website]]
max_ttl                  0s
ttl                      5m


- Read new credentials
# vault read azure/creds/my-role
Key                Value
---                -----
lease_id           azure/creds/my-role/BqHorsQTkp5oFEObHYuShUDz
lease_duration     5m
lease_renewable    true
client_id          71ad1565-574b-4b90-ad12-56912c4ae110
client_secret      74ef4dde-2701-9f29-66f5-f51b4db86224


- To verify

AZ Portal - search for 'App registration', click 'All applications'. In the search bar, copy/paste the client_id
Note - this gets revoked in 5 mins by Vault because of the role we added above.

CLI -

⇒  az ad sp list --query "[?contains(appId, '71ad1565-574b-4b90-ad12-56912c4ae110')]" --all
[
  {
    "accountEnabled": "True",
    "addIns": [],
    "alternativeNames": [],
    "appDisplayName": "vault-4ac2a52f-5ba8-6bf3-efd1-a9f2fdca138b",
    "appId": "71ad1565-574b-4b90-ad12-56912c4ae110",
    "appOwnerTenantId": "0e3e2e88-8caf-41ca-b4da-e3b33b6c52ec",
    "appRoleAssignmentRequired": false,
    "appRoles": [],
    "applicationTemplateId": null,
    "deletionTimestamp": null,
    "displayName": "vault-4ac2a52f-5ba8-6bf3-efd1-a9f2fdca138b",
    "errorUrl": null,
    "homepage": "https://vault-4ac2a52f-5ba8-6bf3-efd1-a9f2fdca138b",
    "informationalUrls": {
      "marketing": null,
      "privacy": null,
      "support": null,
      "termsOfService": null
    },
    "keyCredentials": [],
    "logoutUrl": null,
    "notificationEmailAddresses": [],
    "oauth2Permissions": [
      {
        "adminConsentDescription": "Allow the application to access vault-4ac2a52f-5ba8-6bf3-efd1-a9f2fdca138b on behalf of the signed-in user.",
        "adminConsentDisplayName": "Access vault-4ac2a52f-5ba8-6bf3-efd1-a9f2fdca138b",
        "id": "fc040adc-374a-4a84-a9f3-47d46bf5926c",
        "isEnabled": true,
        "type": "User",
        "userConsentDescription": "Allow the application to access vault-4ac2a52f-5ba8-6bf3-efd1-a9f2fdca138b on your behalf.",
        "userConsentDisplayName": "Access vault-4ac2a52f-5ba8-6bf3-efd1-a9f2fdca138b",
        "value": "user_impersonation"
      }
    ],
    "objectId": "5abde33f-0998-4adb-bf97-5fb435f12d57",
    "objectType": "ServicePrincipal",
    "odata.type": "Microsoft.DirectoryServices.ServicePrincipal",
    "passwordCredentials": [
      {
        "additionalProperties": null,
        "customKeyIdentifier": null,
        "endDate": "2029-10-13T03:05:56.216504+00:00",
        "keyId": "da164420-ed28-4354-88b5-d1d3c88e0a2d",
        "startDate": "2019-10-16T03:05:56.216504+00:00",
        "value": null
      }
    ],
    "preferredSingleSignOnMode": null,
    "preferredTokenSigningKeyEndDateTime": null,
    "preferredTokenSigningKeyThumbprint": null,
    "publisherName": "Default Directory",
    "replyUrls": [],
    "samlMetadataUrl": null,
    "samlSingleSignOnSettings": null,
    "servicePrincipalNames": [
      "https://vault-4ac2a52f-5ba8-6bf3-efd1-a9f2fdca138b",
      "71ad1565-574b-4b90-ad12-56912c4ae110"
    ],
    "servicePrincipalType": "Application",
    "signInAudience": "AzureADMyOrg",
    "tags": [],
    "tokenEncryptionKeyId": null
  }
]






No comments:

Post a Comment