From ce1312003b1f6b0f9e688cf425bd2078ef1a4f2f Mon Sep 17 00:00:00 2001 From: Shawn Meyer <49066369+shawntmeyer@users.noreply.github.com> Date: Tue, 18 Apr 2023 13:08:00 -0400 Subject: [PATCH] [Modules] New Microsoft.Compute/sshPublicKey (#2673) * add sshPublicKey Module * Update modules/Microsoft.Compute/sshPublicKeys/readme.md Co-authored-by: Alexander Sehr * Update modules/Microsoft.Compute/sshPublicKeys/deploy.bicep Co-authored-by: Alexander Sehr * Update modules/Microsoft.Compute/sshPublicKeys/.test/common/dependencies.bicep Co-authored-by: Alexander Sehr * Update modules/Microsoft.Compute/sshPublicKeys/.test/common/deploy.test.bicep Co-authored-by: Alexander Sehr * Update modules/Microsoft.Compute/sshPublicKeys/.test/min/deploy.test.bicep Co-authored-by: Alexander Sehr * Update modules/Microsoft.Compute/sshPublicKeys/readme.md Co-authored-by: Alexander Sehr * Update modules/Microsoft.Compute/sshPublicKeys/deploy.bicep Co-authored-by: Alexander Sehr * Update modules/Microsoft.Compute/sshPublicKeys/deploy.bicep Co-authored-by: Alexander Sehr * resolved comments * updated readme and nested role assignments * added ! --------- Co-authored-by: Shawn Meyer Co-authored-by: Alexander Sehr --- .../ms.compute.sshpublickeys.yml | 50 ++++ .../workflows/ms.compute.sshpublickeys.yml | 165 ++++++++++++ .../.bicep/nested_roleAssignments.bicep | 90 +++++++ .../.test/common/dependencies.bicep | 61 +++++ .../.test/common/deploy.test.bicep | 54 ++++ .../sshPublicKeys/.test/min/deploy.test.bicep | 41 +++ .../sshPublicKeys/deploy.bicep | 80 ++++++ .../Microsoft.Compute/sshPublicKeys/readme.md | 254 ++++++++++++++++++ .../sshPublicKeys/version.json | 4 + 9 files changed, 799 insertions(+) create mode 100644 .azuredevops/modulePipelines/ms.compute.sshpublickeys.yml create mode 100644 .github/workflows/ms.compute.sshpublickeys.yml create mode 100644 modules/Microsoft.Compute/sshPublicKeys/.bicep/nested_roleAssignments.bicep create mode 100644 modules/Microsoft.Compute/sshPublicKeys/.test/common/dependencies.bicep create mode 100644 modules/Microsoft.Compute/sshPublicKeys/.test/common/deploy.test.bicep create mode 100644 modules/Microsoft.Compute/sshPublicKeys/.test/min/deploy.test.bicep create mode 100644 modules/Microsoft.Compute/sshPublicKeys/deploy.bicep create mode 100644 modules/Microsoft.Compute/sshPublicKeys/readme.md create mode 100644 modules/Microsoft.Compute/sshPublicKeys/version.json diff --git a/.azuredevops/modulePipelines/ms.compute.sshpublickeys.yml b/.azuredevops/modulePipelines/ms.compute.sshpublickeys.yml new file mode 100644 index 0000000000..b45dc54455 --- /dev/null +++ b/.azuredevops/modulePipelines/ms.compute.sshpublickeys.yml @@ -0,0 +1,50 @@ +name: 'Compute - SshPublicKeys' + +parameters: + - name: staticValidation + displayName: Execute static validation + type: boolean + default: true + - name: deploymentValidation + displayName: Execute deployment validation + type: boolean + default: true + - name: removeDeployment + displayName: Remove deployed module + type: boolean + default: true + - name: prerelease + displayName: Publish prerelease module + type: boolean + default: false + +pr: none + +trigger: + batch: true + branches: + include: + - main + paths: + include: + - '/.azuredevops/modulePipelines/ms.compute.sshpublickeys.yml' + - '/.azuredevops/pipelineTemplates/*.yml' + - '/modules/Microsoft.Compute/sshPublicKeys/*' + - '/utilities/pipelines/*' + exclude: + - '/utilities/pipelines/deploymentRemoval/*' + - '/**/*.md' + +variables: + - template: '../../settings.yml' + - group: 'PLATFORM_VARIABLES' + - name: modulePath + value: '/modules/Microsoft.Compute/sshPublicKeys' + +stages: + - template: /.azuredevops/pipelineTemplates/stages.module.yml + parameters: + staticValidation: '${{ parameters.staticValidation }}' + deploymentValidation: '${{ parameters.deploymentValidation }}' + removeDeployment: '${{ parameters.removeDeployment }}' + prerelease: '${{ parameters.prerelease }}' diff --git a/.github/workflows/ms.compute.sshpublickeys.yml b/.github/workflows/ms.compute.sshpublickeys.yml new file mode 100644 index 0000000000..8ef45a5dd8 --- /dev/null +++ b/.github/workflows/ms.compute.sshpublickeys.yml @@ -0,0 +1,165 @@ +name: 'Compute: SshPublicKeys' + +on: + workflow_dispatch: + inputs: + staticValidation: + type: boolean + description: 'Execute static validation' + required: false + default: true + deploymentValidation: + type: boolean + description: 'Execute deployment validation' + required: false + default: true + removeDeployment: + type: boolean + description: 'Remove deployed module' + required: false + default: true + prerelease: + type: boolean + description: 'Publish prerelease module' + required: false + default: false + push: + branches: + - main + paths: + - '.github/actions/templates/**' + - '.github/workflows/ms.compute.sshpublickeys.yml' + - 'modules/Microsoft.Compute/sshPublicKeys/**' + - 'utilities/pipelines/**' + - '!utilities/pipelines/deploymentRemoval/**' + - '!*/**/readme.md' + +env: + variablesPath: 'settings.yml' + modulePath: 'modules/Microsoft.Compute/sshPublicKeys' + workflowPath: '.github/workflows/ms.compute.sshPublicKeys.yml' + AZURE_CREDENTIALS: ${{ secrets.AZURE_CREDENTIALS }} + ARM_SUBSCRIPTION_ID: '${{ secrets.ARM_SUBSCRIPTION_ID }}' + ARM_MGMTGROUP_ID: '${{ secrets.ARM_MGMTGROUP_ID }}' + ARM_TENANT_ID: '${{ secrets.ARM_TENANT_ID }}' + TOKEN_NAMEPREFIX: '${{ secrets.TOKEN_NAMEPREFIX }}' + +concurrency: + group: ${{ github.workflow }} + +jobs: + ########################### + # Initialize pipeline # + ########################### + job_initialize_pipeline: + runs-on: ubuntu-20.04 + name: 'Initialize pipeline' + steps: + - name: 'Checkout' + uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: 'Set input parameters to output variables' + id: get-workflow-param + uses: ./.github/actions/templates/getWorkflowInput + with: + workflowPath: '${{ env.workflowPath}}' + - name: 'Get parameter file paths' + id: get-module-test-file-paths + uses: ./.github/actions/templates/getModuleTestFiles + with: + modulePath: '${{ env.modulePath }}' + outputs: + workflowInput: ${{ steps.get-workflow-param.outputs.workflowInput }} + moduleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.moduleTestFilePaths }} + + ######################### + # Static validation # + ######################### + job_module_static_validation: + runs-on: ubuntu-20.04 + name: 'Static validation' + if: (fromJson(needs.job_initialize_pipeline.outputs.workflowInput)).staticValidation == 'true' + needs: + - job_initialize_pipeline + steps: + - name: 'Checkout' + uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Set environment variables + uses: ./.github/actions/templates/setEnvironmentVariables + with: + variablesPath: ${{ env.variablesPath }} + - name: 'Run tests' + uses: ./.github/actions/templates/validateModulePester + with: + modulePath: '${{ env.modulePath }}' + moduleTestFilePath: '${{ env.moduleTestFilePath }}' + + ############################# + # Deployment validation # + ############################# + job_module_deploy_validation: + runs-on: ubuntu-20.04 + name: 'Deploying' + if: | + !cancelled() && + (fromJson(needs.job_initialize_pipeline.outputs.workflowInput)).deploymentValidation == 'true' && + needs.job_module_static_validation.result != 'failure' + needs: + - job_initialize_pipeline + - job_module_static_validation + strategy: + fail-fast: false + matrix: + moduleTestFilePaths: ${{ fromJson(needs.job_initialize_pipeline.outputs.moduleTestFilePaths) }} + steps: + - name: 'Checkout' + uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Set environment variables + uses: ./.github/actions/templates/setEnvironmentVariables + with: + variablesPath: ${{ env.variablesPath }} + - name: 'Using test file [${{ matrix.moduleTestFilePaths }}]' + uses: ./.github/actions/templates/validateModuleDeployment + with: + templateFilePath: '${{ env.modulePath }}/${{ matrix.moduleTestFilePaths }}' + location: '${{ env.location }}' + subscriptionId: '${{ secrets.ARM_SUBSCRIPTION_ID }}' + managementGroupId: '${{ secrets.ARM_MGMTGROUP_ID }}' + removeDeployment: '${{ (fromJson(needs.job_initialize_pipeline.outputs.workflowInput)).removeDeployment }}' + + ################## + # Publishing # + ################## + job_publish_module: + name: 'Publishing' + if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master' || github.event.inputs.prerelease == 'true' + runs-on: ubuntu-20.04 + needs: + - job_module_deploy_validation + steps: + - name: 'Checkout' + uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Set environment variables + uses: ./.github/actions/templates/setEnvironmentVariables + with: + variablesPath: ${{ env.variablesPath }} + - name: 'Publishing' + uses: ./.github/actions/templates/publishModule + with: + templateFilePath: '${{ env.modulePath }}/deploy.bicep' + templateSpecsRGName: '${{ env.templateSpecsRGName }}' + templateSpecsRGLocation: '${{ env.templateSpecsRGLocation }}' + templateSpecsDescription: '${{ env.templateSpecsDescription }}' + templateSpecsDoPublish: '${{ env.templateSpecsDoPublish }}' + bicepRegistryName: '${{ env.bicepRegistryName }}' + bicepRegistryRGName: '${{ env.bicepRegistryRGName }}' + bicepRegistryRgLocation: '${{ env.bicepRegistryRgLocation }}' + bicepRegistryDoPublish: '${{ env.bicepRegistryDoPublish }}' + publishLatest: '${{ env.publishLatest }}' diff --git a/modules/Microsoft.Compute/sshPublicKeys/.bicep/nested_roleAssignments.bicep b/modules/Microsoft.Compute/sshPublicKeys/.bicep/nested_roleAssignments.bicep new file mode 100644 index 0000000000..b7f80f662b --- /dev/null +++ b/modules/Microsoft.Compute/sshPublicKeys/.bicep/nested_roleAssignments.bicep @@ -0,0 +1,90 @@ +@sys.description('Required. The IDs of the principals to assign the role to.') +param principalIds array + +@sys.description('Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead.') +param roleDefinitionIdOrName string + +@sys.description('Required. The resource ID of the resource to apply the role assignment to.') +param resourceId string + +@sys.description('Optional. The principal type of the assigned principal ID.') +@allowed([ + 'ServicePrincipal' + 'Group' + 'User' + 'ForeignGroup' + 'Device' + '' +]) +param principalType string = '' + +@sys.description('Optional. The description of the role assignment.') +param description string = '' + +@sys.description('Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase "foo_storage_container".') +param condition string = '' + +@sys.description('Optional. Version of the condition.') +@allowed([ + '2.0' +]) +param conditionVersion string = '2.0' + +@sys.description('Optional. Id of the delegated managed identity resource.') +param delegatedManagedIdentityResourceId string = '' + +var builtInRoleNames = { + 'Avere Contributor': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4f8fab4f-1852-4a58-a46a-8eaf358af14a') + 'Avere Operator': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c025889f-8102-4ebf-b32c-fc0c6f0c6bd9') + 'Azure Center for SAP solutions administrator': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7b0c7e81-271f-4c71-90bf-e30bdfdbc2f7') + 'Azure Center for SAP solutions reader': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '05352d14-a920-4328-a0de-4cbe7430e26b') + 'Azure Center for SAP solutions service role': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'aabbc5dd-1af0-458b-a942-81af88f9c138') + 'Azure Kubernetes Service Policy Add-on Deployment': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18ed5180-3e48-46fd-8541-4ea054d57064') + 'Compute Gallery Sharing Admin': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '1ef6a3be-d0ac-425d-8c01-acb62866290b') + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + 'Data Operator for Managed Disks': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '959f8984-c045-4866-89c7-12bf9737be2e') + 'Desktop Virtualization Power On Contributor': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '489581de-a3bd-480d-9518-53dea7416b33') + 'Desktop Virtualization Power On Off Contributor': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '40c5ff49-9181-41f8-ae61-143b0e78555e') + 'Desktop Virtualization Virtual Machine Contributor': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a959dbd1-f747-45e3-8ba6-dd80f235f97c') + 'DevTest Labs User': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '76283e04-6283-4c54-8f91-bcf1374a3c64') + 'Disk Backup Reader': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '3e5e47e6-65f7-47ef-90b5-e5dd4d455f24') + 'Disk Pool Operator': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '60fc6e62-5479-42d4-8bf4-67625fcc2840') + 'Disk Restore Operator': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b50d9833-a0cb-478e-945f-707fcc997c13') + 'Disk Snapshot Contributor': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7efff54f-a5b4-42b5-a1c5-5411624893ce') + 'Log Analytics Contributor': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '92aaf0da-9dab-42b6-94a3-d43ce8d16293') + 'Log Analytics Reader': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '73c42c96-874c-492b-b04d-ab87d138a893') + 'Managed Application Contributor Role': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '641177b8-a67a-45b9-a033-47bc880bb21e') + 'Managed Application Operator Role': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c7393b34-138c-406f-901b-d8cf2b17e6ae') + 'Managed Applications Reader': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b9331d33-8a36-4f8c-b097-4f54124fdb44') + 'Monitoring Contributor': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '749f88d5-cbae-40b8-bcfc-e573ddc772fa') + 'Monitoring Reader': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '43d0d8ad-25c7-4714-9337-8ba259a9fe05') + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Reservation Purchaser': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f7b75c60-3036-4b75-91c3-6b41c27c1689') + 'Resource Policy Contributor': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '36243c78-bf99-498c-9df9-86d9f8d28608') + 'Role Based Access Control Administrator (Preview)': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168') + 'User Access Administrator': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9') + 'Virtual Machine Administrator Login': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '1c0163c0-47e6-4577-8991-ea5c82e286e4') + 'Virtual Machine Contributor': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '9980e02c-c2be-4d73-94e8-173b1dc7cf3c') + 'Virtual Machine User Login': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'fb879df8-f326-4884-b1cf-06f3ad86be52') + 'VM Scanner Operator': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'd24ecba3-c1f4-40fa-a7bb-4588a071e8fd') + 'Windows Admin Center Administrator Login': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a6333a3e-0164-44c3-b281-7a577aff287f') +} + +resource sshKey 'Microsoft.Compute/sshPublicKeys@2022-11-01' existing = { + name: last(split(resourceId, '/'))! +} + +resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for principalId in principalIds: { + name: guid(resourceId, principalId, roleDefinitionIdOrName) + properties: { + description: description + roleDefinitionId: contains(builtInRoleNames, roleDefinitionIdOrName) ? builtInRoleNames[roleDefinitionIdOrName] : roleDefinitionIdOrName + principalId: principalId + principalType: !empty(principalType) ? any(principalType) : null + condition: !empty(condition) ? condition : null + conditionVersion: !empty(conditionVersion) && !empty(condition) ? conditionVersion : null + delegatedManagedIdentityResourceId: !empty(delegatedManagedIdentityResourceId) ? delegatedManagedIdentityResourceId : null + } + scope: sshKey +}] diff --git a/modules/Microsoft.Compute/sshPublicKeys/.test/common/dependencies.bicep b/modules/Microsoft.Compute/sshPublicKeys/.test/common/dependencies.bicep new file mode 100644 index 0000000000..27b6f54c35 --- /dev/null +++ b/modules/Microsoft.Compute/sshPublicKeys/.test/common/dependencies.bicep @@ -0,0 +1,61 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Optional. Name of the Deployment Script that creates the SSH Public Key.') +param generateSshPubKeyScriptName string + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +@description('Required. Name of the temporary SSH Public Key to create for test.') +param sshKeyName string + +@description('Optional. Do not provide a value. Used to force the deployment script to rerun on every redeployment.') +param utcValue string = utcNow() + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +// required for the deployment script to create a new temporary ssh public key object +resource msi_ContributorRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(resourceGroup().id, 'ManagedIdentityContributor', '<>') + properties: { + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') // Contributor + principalId: managedIdentity.properties.principalId + principalType: 'ServicePrincipal' + } +} + +resource createPubKeyScript 'Microsoft.Resources/deploymentScripts@2020-10-01' = { + name: generateSshPubKeyScriptName + location: location + kind: 'AzurePowerShell' + identity: { + type: 'UserAssigned' + userAssignedIdentities: { + '${managedIdentity.id}': {} + } + } + properties: { + azPowerShellVersion: '8.0' + retentionInterval: 'P1D' + arguments: '-ResourceGroupName ${resourceGroup().name} -SSHKeyName ${sshKeyName}' + scriptContent: loadTextContent('../../../../.shared/.scripts/New-SSHKey.ps1') + cleanupPreference: 'OnExpiration' + forceUpdateTag: utcValue + } + dependsOn: [ + msi_ContributorRoleAssignment + ] +} + +@description('The public key to be added to the SSH Public Key resource.') +output publicKey string = createPubKeyScript.properties.outputs.pubKey + +@description('The resource ID of the managed Identity') +output managedIdentityId string = managedIdentity.id + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/modules/Microsoft.Compute/sshPublicKeys/.test/common/deploy.test.bicep b/modules/Microsoft.Compute/sshPublicKeys/.test/common/deploy.test.bicep new file mode 100644 index 0000000000..1bd8893349 --- /dev/null +++ b/modules/Microsoft.Compute/sshPublicKeys/.test/common/deploy.test.bicep @@ -0,0 +1,54 @@ +targetScope = 'subscription' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'ms.compute.sshPublicKeys-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param location string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +@maxLength(7) +param serviceShort string = 'cspkcom' + +@description('Optional. Enable telemetry via a Globally Unique Identifier (GUID).') +param enableDefaultTelemetry bool = true + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: location +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, location)}-nestedDependencies' + params: { + generateSshPubKeyScriptName: 'dep-<>-ds-${serviceShort}-generateSshPubKey' + sshKeyName: 'dep-<>-ssh-${serviceShort}' + managedIdentityName: 'dep-<>-msi-${serviceShort}' + } +} + +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../deploy.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, location)}-test-${serviceShort}' + params: { + enableDefaultTelemetry: enableDefaultTelemetry + name: '<>-sshkey-${serviceShort}001' + publicKey: nestedDependencies.outputs.publicKey + } +} diff --git a/modules/Microsoft.Compute/sshPublicKeys/.test/min/deploy.test.bicep b/modules/Microsoft.Compute/sshPublicKeys/.test/min/deploy.test.bicep new file mode 100644 index 0000000000..5f5403280f --- /dev/null +++ b/modules/Microsoft.Compute/sshPublicKeys/.test/min/deploy.test.bicep @@ -0,0 +1,41 @@ +targetScope = 'subscription' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'ms.compute.sshPublicKeys-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param location string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'cspkmin' + +@description('Optional. Enable telemetry via a Globally Unique Identifier (GUID).') +param enableDefaultTelemetry bool = true + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: location +} + +// ============== // +// Test Execution // +// ============== // +module testDeployment '../../deploy.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, location)}-test-${serviceShort}' + params: { + enableDefaultTelemetry: enableDefaultTelemetry + name: '<>-${serviceShort}001' + } +} diff --git a/modules/Microsoft.Compute/sshPublicKeys/deploy.bicep b/modules/Microsoft.Compute/sshPublicKeys/deploy.bicep new file mode 100644 index 0000000000..8c90d6e241 --- /dev/null +++ b/modules/Microsoft.Compute/sshPublicKeys/deploy.bicep @@ -0,0 +1,80 @@ +@description('Required. The name of the SSH public Key that is being created.') +param name string + +@description('Optional. Resource location.') +param location string = resourceGroup().location + +@description('Optional. SSH public key used to authenticate to a virtual machine through SSH. If this property is not initially provided when the resource is created, the publicKey property will be populated when generateKeyPair is called. If the public key is provided upon resource creation, the provided public key needs to be at least 2048-bit and in ssh-rsa format.') +param publicKey string = '' + +@allowed([ + '' + 'CanNotDelete' + 'ReadOnly' +]) +@description('Optional. Specify the type of lock.') +param lock string = '' + +@description('Optional. Array of role assignment objects that contain the \'roleDefinitionIdOrName\' and \'principalId\' to define RBAC role assignments on this resource. In the roleDefinitionIdOrName attribute, you can provide either the display name of the role definition, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') +param roleAssignments array = [] + +@description('Optional. Tags of the availability set resource.') +param tags object = {} + +@description('Optional. Enable telemetry via a Globally Unique Identifier (GUID).') +param enableDefaultTelemetry bool = true + +resource defaultTelemetry 'Microsoft.Resources/deployments@2021-04-01' = if (enableDefaultTelemetry) { + name: 'pid-47ed15a6-730a-4827-bcb4-0fd963ffbd82-${uniqueString(deployment().name, location)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + } + } +} + +resource sshPublicKey 'Microsoft.Compute/sshPublicKeys@2022-08-01' = { + name: name + location: location + tags: tags + properties: { + publicKey: !empty(publicKey) ? publicKey : null + } +} + +resource sshPublicKey_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock)) { + name: '${sshPublicKey.name}-${lock}-lock' + properties: { + level: any(lock) + notes: lock == 'CanNotDelete' ? 'Cannot delete resource or child resources.' : 'Cannot modify the resource or child resources.' + } + scope: sshPublicKey +} + +module sshPublicKey_roleAssignments '.bicep/nested_roleAssignments.bicep' = [for (roleAssignment, index) in roleAssignments: { + name: '${uniqueString(deployment().name, location)}-sshPublicKey-Rbac-${index}' + params: { + description: contains(roleAssignment, 'description') ? roleAssignment.description : '' + principalIds: roleAssignment.principalIds + principalType: contains(roleAssignment, 'principalType') ? roleAssignment.principalType : '' + roleDefinitionIdOrName: roleAssignment.roleDefinitionIdOrName + condition: contains(roleAssignment, 'condition') ? roleAssignment.condition : '' + delegatedManagedIdentityResourceId: contains(roleAssignment, 'delegatedManagedIdentityResourceId') ? roleAssignment.delegatedManagedIdentityResourceId : '' + resourceId: sshPublicKey.id + } +}] + +@description('The name of the Resource Group the Public SSH Key was created in.') +output resourceGroupName string = resourceGroup().name + +@description('The resource ID of the Public SSH Key.') +output resourceId string = sshPublicKey.id + +@description('The name of the Public SSH Key.') +output name string = sshPublicKey.name + +@description('The location the resource was deployed into.') +output location string = sshPublicKey.location diff --git a/modules/Microsoft.Compute/sshPublicKeys/readme.md b/modules/Microsoft.Compute/sshPublicKeys/readme.md new file mode 100644 index 0000000000..eb33edd4ea --- /dev/null +++ b/modules/Microsoft.Compute/sshPublicKeys/readme.md @@ -0,0 +1,254 @@ +# Public SSH Keys `[Microsoft.Compute/sshPublicKeys]` + +This template deploys a Public SSH Key resource. +> Note: The resource does not auto-generate the key for you. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) +- [Deployment examples](#Deployment-examples) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Authorization/locks` | [2020-05-01](https://docs.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2020-05-01/locks) | +| `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://docs.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Compute/sshPublicKeys` | [2022-08-01](https://docs.microsoft.com/en-us/azure/templates/Microsoft.Compute/2022-08-01/sshPublicKeys) | + +## Parameters + +**Required parameters** + +| Parameter Name | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the SSH public Key that is being created. | + +**Optional parameters** + +| Parameter Name | Type | Default Value | Allowed Values | Description | +| :-- | :-- | :-- | :-- | :-- | +| `enableDefaultTelemetry` | bool | `True` | | Enable telemetry via a Globally Unique Identifier (GUID). | +| `location` | string | `[resourceGroup().location]` | | Resource location. | +| `lock` | string | `''` | `['', CanNotDelete, ReadOnly]` | Specify the type of lock. | +| `publicKey` | string | `''` | | SSH public key used to authenticate to a virtual machine through SSH. If this property is not initially provided when the resource is created, the publicKey property will be populated when generateKeyPair is called. If the public key is provided upon resource creation, the provided public key needs to be at least 2048-bit and in ssh-rsa format. | +| `roleAssignments` | array | `[]` | | Array of role assignment objects that contain the 'roleDefinitionIdOrName' and 'principalId' to define RBAC role assignments on this resource. In the roleDefinitionIdOrName attribute, you can provide either the display name of the role definition, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | +| `tags` | object | `{object}` | | Tags of the availability set resource. | + + +### Parameter Usage: `roleAssignments` + +Create a role assignment for the given resource. If you want to assign a service principal / managed identity that is created in the same deployment, make sure to also specify the `'principalType'` parameter and set it to `'ServicePrincipal'`. This will ensure the role assignment waits for the principal's propagation in Azure. + +
+ +Parameter JSON format + +```json +"roleAssignments": { + "value": [ + { + "roleDefinitionIdOrName": "Reader", + "description": "Reader Role Assignment", + "principalIds": [ + "12345678-1234-1234-1234-123456789012", // object 1 + "78945612-1234-1234-1234-123456789012" // object 2 + ] + }, + { + "roleDefinitionIdOrName": "/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11", + "principalIds": [ + "12345678-1234-1234-1234-123456789012" // object 1 + ], + "principalType": "ServicePrincipal" + } + ] +} +``` + +
+ +
+ +Bicep format + +```bicep +roleAssignments: [ + { + roleDefinitionIdOrName: 'Reader' + description: 'Reader Role Assignment' + principalIds: [ + '12345678-1234-1234-1234-123456789012' // object 1 + '78945612-1234-1234-1234-123456789012' // object 2 + ] + } + { + roleDefinitionIdOrName: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11' + principalIds: [ + '12345678-1234-1234-1234-123456789012' // object 1 + ] + principalType: 'ServicePrincipal' + } +] +``` + +
+

+ +### Parameter Usage: `tags` + +Tag names and tag values can be provided as needed. A tag can be left without a value. + +

+ +Parameter JSON format + +```json +"tags": { + "value": { + "Environment": "Non-Prod", + "Contact": "test.user@testcompany.com", + "PurchaseOrder": "1234", + "CostCenter": "7890", + "ServiceName": "DeploymentValidation", + "Role": "DeploymentValidation" + } +} +``` + +
+ +
+ +Bicep format + +```bicep +tags: { + Environment: 'Non-Prod' + Contact: 'test.user@testcompany.com' + PurchaseOrder: '1234' + CostCenter: '7890' + ServiceName: 'DeploymentValidation' + Role: 'DeploymentValidation' +} +``` + +
+

+ +## Outputs + +| Output Name | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the Public SSH Key. | +| `resourceGroupName` | string | The name of the Resource Group the Public SSH Key was created in. | +| `resourceId` | string | The resource ID of the Public SSH Key. | + +## Cross-referenced modules + +_None_ + +## Deployment examples + +The following module usage examples are retrieved from the content of the files hosted in the module's `.test` folder. + >**Note**: The name of each example is based on the name of the file from which it is taken. + + >**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +

Example 1: Common

+ +
+ +via Bicep module + +```bicep +module sshPublicKeys './Microsoft.Compute/sshPublicKeys/deploy.bicep' = { + name: '${uniqueString(deployment().name, location)}-test-cspkcom' + params: { + // Required parameters + name: '<>-sshkey-cspkcom001' + // Non-required parameters + enableDefaultTelemetry: '' + publicKey: '' + } +} +``` + +
+

+ +

+ +via JSON Parameter file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "<>-sshkey-cspkcom001" + }, + // Non-required parameters + "enableDefaultTelemetry": { + "value": "" + }, + "publicKey": { + "value": "" + } + } +} +``` + +
+

+ +

Example 2: Min

+ +
+ +via Bicep module + +```bicep +module sshPublicKeys './Microsoft.Compute/sshPublicKeys/deploy.bicep' = { + name: '${uniqueString(deployment().name, location)}-test-cspkmin' + params: { + // Required parameters + name: '<>-cspkmin001' + // Non-required parameters + enableDefaultTelemetry: '' + } +} +``` + +
+

+ +

+ +via JSON Parameter file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "<>-cspkmin001" + }, + // Non-required parameters + "enableDefaultTelemetry": { + "value": "" + } + } +} +``` + +
+

diff --git a/modules/Microsoft.Compute/sshPublicKeys/version.json b/modules/Microsoft.Compute/sshPublicKeys/version.json new file mode 100644 index 0000000000..56f8d9ca40 --- /dev/null +++ b/modules/Microsoft.Compute/sshPublicKeys/version.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json", + "version": "0.4" +}