OpenTofu Provisioner
Massdriver provisioner for managing resources with OpenTofu. You can view the GitHub repository for this provisioner here.
Structure​
This provisioner expects the path to contain an OpenTofu module.
If you wish to use a dependency lock file (.terraform.lock.hcl) with your module, be sure it is in the module directory when you publish with the Massdriver CLI. For this reason, it's best to check this dependency lock file into source control.
Tooling​
The following tools are included in this provisioner:
- Checkov: Included to scan terraform configurations for common policy and compliance violations.
Configuration​
The following configuration options are available:
| Configuration Option | Type | Default | Description |
|---|---|---|---|
log_level | string | null | Sets the TF_LOG environment variable to control OpenTofu log verbosity. Supported values: TRACE, DEBUG, INFO, WARN, ERROR |
json | boolean | false | Enables JSON output for OpenTofu. |
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). |
ssh.private_key | string | null | A private SSH key used to access private module repositories. When set, the provisioner configures SSH authentication and rewrites HTTPS git URLs to use SSH. |
Inputs​
Since OpenTofu is compatible with variables expressed in JSON syntax, both the params and connections are left unmodified and simply copied into the module directory as _params.auto.tfvars.json and _connections.auto.tfvars.json, respectively.
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 generate a _massdriver_variables.tf file with full type expressions for each parameter and connection. If modifications to fields are required, use a locals block to manipulate the data as needed.
Resources​
Resources can be created two ways using this provisioner: using the Massdriver OpenTofu provider, and using OpenTofu outputs. (The Terraform provider resource is named massdriver_artifact for backwards compatibility — it represents a Massdriver resource.)
Massdriver OpenTofu Provider​
Refer to the provider documentation for the massdriver_artifact resource. An example is below:
resource "massdriver_artifact" "bucket" {
field = "bucket"
provider_resource_id = aws_s3_bucket.main.arn
name = "AWS S3 Bucket: ${aws_s3_bucket.main.arn}"
artifact = jsonencode(
{
data = {
infrastructure = {
arn = aws_s3_bucket.main.arn
}
}
specs = {
aws = {
region = var.bucket.region
}
}
}
)
}
OpenTofu Outputs​
After every provision, this provider will scan the module 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 resource. The file pattern uses the legacy artifact_ prefix; the underlying provisioner contract is being updated separately.
{
"params": {
...
},
"connections": {
...
},
"envs": {
...
},
"secrets": {
...
},
"outputs": {
...
}
}
To demonstrate, let's say there is an AWS S3 bucket bundle with a single param (region), a single connection (aws_iam_role), and a single resource (bucket). The massdriver.yaml would be similar to:
params:
required:
- region
properties:
region:
type: string
connections:
required:
- aws_authentication
properties:
aws_authentication:
$ref: aws-iam-role
artifacts:
required:
- bucket
properties:
bucket:
$ref: aws-s3-bucket
Since the resource is named bucket a file named artifact_bucket.jq would need to be in the module 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 resource structure:
- Fully render the resource in the OpenTofu output
- Build the resource using the jq template
Here are examples of each approach.
Fully Render as OpenTofu Output​
If you choose to fully render the resource in OpenTofu, it would be similar to:
output "artifact_bucket" {
value = {
data = {
infrastructure = {
arn = aws_s3_bucket.main.arn
}
}
specs = {
aws = {
region = var.region
}
}
}
}
In this case, the input to the artifact_bucket.jq template file would be:
{
"params": {
"region": "us-east-1"
},
"connections": {
"aws_authentication": {
"data": {
"arn": "arn:aws:iam::012345678910:role/role_name",
"external_id": "s0mes3cr3tv@lue"
}
}
},
"envs": {},
"secrets": {},
"outputs": {
"artifact_bucket": {
"data": {
"infrastructure": {
"arn": "arn:aws:s3:::the_bucket_name"
}
},
"specs": {
"aws": {
"region": "us-east-1"
}
}
}
}
}
Thus, the artifact_bucket.jq file would simply be:
.outputs.artifact_bucket
Build Resource in JQ Template​
Alternatively, you can build the resource using the JQ template. This approach is best if you are attempting to minimize changes to your OpenTofu module. With this approach, all you would need to output is the bucket ARN.
output "bucket_arn" {
value = aws_s3_bucket.main.arn
}
In this case, the input to the artifact_bucket.jq template file would be:
{
"params": {
"region": "us-east-1"
},
"connections": {
"aws_authentication": {
"data": {
"arn": "arn:aws:iam::012345678910:role/role_name",
"external_id": "s0mes3cr3tv@lue"
}
}
},
"outputs": {
"bucket_arn": "arn:aws:s3:::the_bucket_name"
}
}
Now the resource structure must be built through the artifact_bucket.jq template:
{
"data": {
"infrastructure": {
"arn": .outputs.bucket_arn
}
},
"specs": {
"aws": {
"region": .params.region
}
}
}