Skip to content

Latest commit

 

History

History
244 lines (200 loc) · 8.44 KB

README.md

File metadata and controls

244 lines (200 loc) · 8.44 KB

bicep

Massdriver Bicep Provisioner

Massdriver provisioner for managing resources with Bicep.

Structure

This provisioner expects the path to contain a single bicep file named template.bicep. While other files may exists in the directory, this template.bicep file will be what is used for provisioning and managing the Azure resources.

Tooling

The following tools are included in this provisioner:

  • Checkov: Included to scan bicep templates for common policy and compliance violations.

Configuration

The following configuration options are available:

Configuration Option Type Default Description
azure_service_principal object .connections.azure_service_principal jq path to a massdriver/azure-service-principal connection for authentication to Azure
region string "eastus" Azure region to deploy template resources into. Defaults to "eastus".
resource_group string <package name> Specifies the resource group name. Defaults to the Massdriver package name if not specified.
delete_resource_group boolean true Determines whether the resource group will be deleted during decommissioning.
checkov.enable boolean true Enables Checkov policy evaluation. If false, Checkov will not be run.
checkov.quiet boolean true Only display failed checks if true (adds the --quiet flag).
checkov.halt_on_failure boolean false Halt provisioning run and mark deployment as failed on a policy failure (removes the --soft-fail flag).

Inputs

Bicep accepts parameters in JSON format. However, Bicep expects the parameters to have a specific structure, where top level keys are unchanged, but the values are nested under a value key. For example, the following JSON object:

{
    "foo": "bar",
    "baz": {
        "nested": "field"
    }
}

Needs to be changed to:

{
    "foo": {
        "value": "bar"
    },
    "baz": {
        "value": {
            "nested": "field"
        }
    }
}

This restructuring is performed automatically by the provisioner on params and connections before passing them to Bicep.

In order to view the structure of the params and connections fields you can run mass bundle build with the Massdriver CLI, and it will append Bicep parameter definitions to the end of the template.bicep file with full type expressions. If modifications to fields are required, use Bicep variables to manipulate the values as needed.

Artifacts

After every provision, this provider will scan the template directory for files matching the pattern artifact_<name>.jq. If a file matching this pattern is present, it will be used as a JQ template to render and publish a Massdriver artifact. The inputs to the JQ template will be a JSON object with the params, connections and Bicep outputs as top level fields. The outputs field is copied directly from the output of the Bicep command. These output fields have the same format mentioned in the above Inputs section, where the value of the output is nested underneath a value block. This is something to be aware of when referencing the values in a Bicep output. You'll see this pattern reflected in the examples below.

{
    "params": {
        ...
    },
    "connections": {
        ...
    },
    "outputs": {
        ...
    }
}

To demonstrate, let's say there is a Azure Storage Account bundle with a single param (region), a single connection (azure_service_principal), and a single artifact (storage_account). The massdriver.yaml would be similar to:

params:
  required:
    - region
  properties:
    region:
      type: string

connections:
  required:
    - azure_service_principal
  properties:
    azure_service_principal:
      $ref: massdriver/azure-service-principal

artifacts:
  required:
    - storage_account
  properties:
    storage_account:
      $ref: massdriver/azure-storage-account-blob

Since the artifact is named storage_account a file named artifact_storage_account.jq would need to be in the template directory and the provisioner would use this file as a JQ template, passing the params, connections and outputs to it. There are two approaches to building the proper artifact structure:

  1. Fully render the artifact in the Bicep output
  2. Build the artifact structure using the JQ template

Here are examples of each approach.

Fully Render as Bicep Output

If you choose to fully render the artifact in a Bicep output, it would be similar to:

param region string

resource storageAccount 'Microsoft.Storage/storageAccounts@2021-04-01' = {
  ...
}

output artifact_storage_account object = {
    data:  {
        infrastructure: {
            ari: storageAccount.id
            endpoint: storageAccount.properties.primaryEndpoints.blob
        }
        security: {}
    }
    specs: {
        azure: {
            region: region
        }
    }
}

In this case, the input to the artifact_storage_account.jq template file would be:

{
    "params": {
        "region": "eastus"
    },
    "connections": {
        "azure_service_principal": {
            "data": {
                "client_id": "00000000-1111-2222-3333-444444444444",
                "client_secret": "s0mes3cr3tv@lue",
                "subscription_id": "00000000-1111-2222-3333-444444444444",
                "tenant_id": "00000000-1111-2222-3333-444444444444"
            }
        }
    },
    "outputs": {
        "artifact_storage_account": {
            "value": {
                "data": {
                    "infrastructure": {
                        "ari": "/subscriptions/00000000-1111-2222-3333-444444444444/resourceGroups/resource-group-name/providers/Microsoft.Storage/storageAccounts/storageaccountname",
                        "endpoint": "https://storageaccountname.blob.core.windows.net/"
                    },
                    "security": {}
                },
                "specs": {
                    "azure": {
                        "region": "eastus"
                    }
                }
            }
        }
    }
}

Thus, the artifact_storage_account.jq file would simply be:

.outputs.artifact_storage_account.value

Build Artifact in JQ Template

Alternatively, you can build the artifact structure using the JQ template. This approach is best if you are attempting to minimize changes to your Bicep template. With this approach, you would need to output the storage account ID and endpoint.

resource storageAccount 'Microsoft.Storage/storageAccounts@2021-04-01' = {
  ...
}

output storageAccountId string = storageAccount.id
output storageAccountEndpoint string = storageAccount.properties.primaryEndpoints.blob

In this case, the input to the artifact_storage_account.jq template file would be:

{
    "params": {
        "region": "eastus"
    },
    "connections": {
        "azure_service_principal": {
            "data": {
                "client_id": "00000000-1111-2222-3333-444444444444",
                "client_secret": "s0mes3cr3tv@lue",
                "subscription_id": "00000000-1111-2222-3333-444444444444",
                "tenant_id": "00000000-1111-2222-3333-444444444444"
            }
        }
    },
    "outputs": {
        "storageAccountEndpoint": {
            "type": "String",
            "value": "https://storageaccountname.blob.core.windows.net/"
        },
        "storageAccountId": {
            "type": "String",
            "value": "/subscriptions/00000000-1111-2222-3333-444444444444/resourceGroups/resource-group-name/providers/Microsoft.Storage/storageAccounts/storageaccountname"
        }
    }
}

Now the artifact structure must be built through the artifact_storage_account.jq template:

{
    "data":  {
        "infrastructure": {
            "ari": .outputs.storageAccountId.value,
            "endpoint": .outputs.storageAccountEndpoint.value
        },
        "security": {}
    },
    "specs": {
        "azure": {
            "region": .params.region
        }
    }
}