#opentofu (2024-03)
Discuss OpenTofu-related topics
2024-03-05
Is this the Signature validation something I could fix on my own or is this something that the provider publishers (ex. github and opsgenie) need to do on their end when publishing?
the provider authors need to submit GPG keys to the OpenTofu Registry. https://github.com/opentofu/registry?tab=readme-ov-file
Just submitted issues to each provider asking them to submit their keys to Opentofu registry using the link you shared. Thank you!
Mind linking those and I’ll thumsbup? We’ve opened 3. Luckily Andriy closed the CP one quickly. So did the SOPS provider. We’re now waiting on Tailscale. Not a major issue or anything, but it is nice to not run into warnings in tofu when you first run it.
Hey Opentofu dev here, please let me know if us reaching out to them would help in any way.
Hey James, i saw Kuba left a note here: https://github.com/integrations/terraform-provider-github/issues/2183
So i let them know the same details for opsgenie here: https://github.com/opsgenie/terraform-provider-opsgenie/issues/428
Now we just wait…
2024-03-06
2024-03-14
v1.7.0-alpha1: [State Encryption] Compliance tests (#1377) Signed-off-by: Janos [email protected] (<mailto:[email protected]>)
:warning: Do not use this release for production workloads! :warning:
It’s time for the first prerelease of the 1.7.0 version! This includes a lot of major and minor new features, as well as a ton of community contributions!
The highlights are:
• State Encryption (docs)
• Declarative removed
blocks (docs)
Please take the above for a spin and let us know your feedback!
For all the features, see the detailed changelog.
You can find the full diff here.
v1.7.0-alpha1 Do not use this release for production workloads! It’s time for the first prerelease of the 1.7.0 version! This includes a lot of major and minor new features, as well as a ton of community contributions! The highlights are:
State Encryption (docs) Declarative removed blocks (<a href=”https://1-7-0-alpha1.opentofu.pages.dev/docs/language/resources/syntax/#removing-resources“…
Do not use this release for production workloads! It’s time for the first prerelease of the 1.7.0 version! This includes a lot of major and minor new features, as well as a ton of community c…
Encrypt your state-related data at rest.
Resources correspond to infrastructure objects like virtual networks or compute instances. Learn about resource types, syntax, behavior, and arguments.
2024-03-18
not sure if this worth a try for OpenTofu, https://github.com/hashicorp/terraform/issues/32738
Terraform Version
Terraform v1.3.9
on linux_amd64
Use Cases
There are a great deal of situations where a duplicate resource is deployed to many regions, regardless of cloud (azure/aws/gcloud etc). In these situations, currently a lot of copy/paste boilerplate is required to copy/paste the resource and edit the provider
meta argument to that resource.
It would be beneficial to be able to condense this into 1 resource, utilizing a for_each, and potentially a local or a way to call a provider with many alias (such as multiple provider blocks for aws with different region configs and alias’ for them).
Attempted Solutions
After much research and attempting to use for_each with a local type list of Strings with each alias value, and providing the alias value to the provider
meta argument and failing, I learned that currently terraform cannot facilitate this.
Proposal
There are two ways this could be handled.
Either allow for_each
to take an argument of providers such as:
for_each = provider.aws
with each.key
being the full provider name, so that provider = each.key
would be valid for example:
resource "some_resource" "some_name" {
for_each = provider.aws
provider = each.key
}
OR
Allow provider
to take a string in a for_each
resource, so I could create a local such as:
locals {
regions = ["us-east-1","us-east-2"]
}
resource "some_resource" "some_name" {
for_each = toset(local.regions)
provider = aws[each.key]
}
References
No response
Current Terraform Version
Terraform v0.13.0-beta1
Use-cases
It would be nice to be able to create dynamic providers. The main reason for my usage would be for aws assume_role. I have Terraform to create a number of AWS Subaccounts, and then I want to configure those subaccounts in one apply, instead of breaking them up across multiple apply steps.
Currently this is done via modules, but with 0.12, I had to manually define copies of the modules for each subaccount.
As said by the 0.13 modules doc: https://github.com/hashicorp/terraform/blob/master/website/docs/configuration/modules.html.md#limitations-when-using-module-expansion
Modules using count or for_each cannot include configured provider blocks within the module. Only proxy configuration blocks are allowed.
Attempted Solutions
# Organisational Group for Crimson App.
module "org_crimson_app" {
source = "./modules/organisation-group"
organisation_id = local.root_organisation_id
group_name = "crimson-app"
billing_alert_emails = ["<billing account>"]
accounts = {
production = {}
staging = {}
test = {}
}
zones = {
public = {
create = true
zone_id = ""
domain = "app.crimsoneducation.org"
}
internal = {
create = true
zone_id = ""
domain = "app.crimsoneducation.io"
}
}
master_role_name = local.organisation_root_role
account_owner_username = var.account_owner_username
account_owner_domain = var.account_owner_domain
// Workaround for <https://github.com/hashicorp/terraform/issues/17519>
account_configuration = {
production = module.org_crimson_app_production_config.config
staging = module.org_crimson_app_staging_config.config
test = module.org_crimson_app_test_config.config
}
}
// Workaround for <https://github.com/hashicorp/terraform/issues/17519>
module "org_crimson_app_production_config" {
source = "./modules/organisation-account-config"
account_info = module.org_crimson_app.account_information.production
}
// Workaround for <https://github.com/hashicorp/terraform/issues/17519>
module "org_crimson_app_staging_config" {
source = "./modules/organisation-account-config"
account_info = module.org_crimson_app.account_information.staging
}
// Workaround for <https://github.com/hashicorp/terraform/issues/17519>
module "org_crimson_app_test_config" {
source = "./modules/organisation-account-config"
account_info = module.org_crimson_app.account_information.test
}
Source for ./modules/organisation-group
:
# The Organisational Unit for this group.
resource "aws_organizations_organizational_unit" "unit" {
name = var.group_name
parent_id = var.organisation_id
lifecycle {
prevent_destroy = true
}
}
# The environment accounts.
resource "aws_organizations_account" "environments" {
for_each = var.accounts
parent_id = aws_organizations_organizational_unit.unit.id
# Use account_name if provided, otherwise [group]-[account].
name = local.account_full_name[each.key]
email = "${var.account_owner_username}+aws-org-${local.account_full_name[each.key]}@${var.account_owner_domain}"
role_name = var.master_role_name
lifecycle {
# There is no AWS Organizations API for reading role_name
ignore_changes = [role_name]
prevent_destroy = true
}
}
# Collect all Account Names
locals {
account_full_name = {
for account_name, account in var.accounts :
account_name =>
lookup(account, "account_name", "${var.group_name}-${account_name}")
}
}
...
Source for ./modules/organisation-account-config
:
// Workaround for <https://github.com/hashicorp/terraform/issues/17519>
variable "account_info" {
type = object({
group_name = string
account_name = string
account_full_name = string
alias = string
master_role_arn = string
zones = map(object({
zone_name = string
fqdn = string
}))
add_terraform_bucket = bool
billing_alert_amount = number
billing_alert_currency = string
billing_alert_emails = list(string)
})
}
# Create Provisioner Assuming Child Account Role.
provider "aws" {
region = "ap-southeast-2"
assume_role {
role_arn = var.account_info.master_role_arn
}
}
resource "aws_iam_account_alias" "alias" {
account_alias = var.account_info.alias
}
# Bucket for Terraform State.
resource "aws_s3_bucket" "terraform_state" {
count = var.account_info.add_terraform_bucket ? 1 : 0
bucket = "${var.account_info.account_full_name}-terraform"
versioning {
enabled = true
}
}
# Fix for Issue: <https://medium.com/faun/aws-eks-the-role-is-not-authorized-to-perform-ec2-describeaccountattributes-error-1c6474781b84>
resource "aws_iam_service_linked_role" "elasticloadbalancing" {
aws_service_name = "elasticloadbalancing.amazonaws.com"
}
...
Proposal
Module for_each
:
# Organisational Group for Crimson App.
module "org_crimson_app" {
source = "./modules/organisation-group"
organisation_id = local.root_organisation_id
group_name = "crimson-app"
billing_alert_emails = ["<billing account>"]
accounts = {
production = {}
staging = {}
test = {}
}
zones = {
public = {
create = true
zone_id = ""
domain = "app.crimsoneducation.org"
}
internal = {
create = true
zone_id = ""
domain = "app.crimsoneducation.io"
}
}
master_role_name = local.organisation_root_role
account_owner_username = var.account_owner_username
account_owner_domain = var.account_owner_domain
account_configuration = module.org_crimson_app_config
}
module "org_crimson_app_config" {
for_each = module.org_crimson_app.account_information
source = "./modules/organisation-account-config"
account_info = each.value
}
Provider for_each
:
This doesn’t look as clean, but appeases the docs saying:
In all cases it is recommended to keep explicit provider configurations only in the root module and pass them (whether implicitly or explicitly) down to descendent modules. This avoids the provider configurations from being “lost” when descendent modules are removed from the configuration. It also allows the user of a configuration to determine which providers require credentials by inspecting only the root module.
# Organisational Group for Crimson App.
module "org_crimson_app" {
source = "./modules/organisation-group"
organisation_id = local.root_organisation_id
group_name = "crimson-app"
billing_alert_emails = ["<billing account>"]
accounts = {
production = {}
staging = {}
test = {}
}
zones = {
public = {
create = true
zone_id = ""
domain = "app.crimsoneducation.org"
}
internal = {
create = true
zone_id = ""
domain = "app.crimsoneducation.io"
}
}
master_role_name = local.organisation_root_role
account_owner_username = var.account_owner_username
account_owner_domain = var.account_owner_domain
account_configuration = module.org_crimson_app_config
}
provider "aws" {
for_each = module.org_crimson_app.account_information
alias = each.key
assume_role {
role_arn = each.value.master_role_arn
}
}
module "org_crimson_app_config" {
for_each = module.org_crimson_app.account_information
source = "./modules/organisation-account-config"
providers = {
aws = aws[each.key]
}
account_info = each.value
}
References
• Another user reference…
2024-03-20
Does anyone know of a concise list of features from OpenTofu that diverge from Terraform?
I’m seeing now that there aren’t really that many releases. I can dig through the release notes. But if there is such a list, lmk.
Hi. Opentofu contributor here. There isn’t such a list right now but we are compiling one :) .