Terraform
There are some functions specific to AWS. Other Cloud providers will be added in the future.
Flow Control
Section titled “Flow Control”BigConfig enables you to use Clojure instead of HCL. You should minimize the dynamic features of HCL that you use and use Clojure language features instead. count is an example of dynamic feature that you should avoid. The for expression in Clojure will achieve the same result. sort-nested-map will make sure the the JSON output is always the same, so that you can commit the main.tf.json like you do with main.tf and refactor you Clojure code with confidence because Git will signal to you unexpected changes of main.tf.json.
The sort-nested-map function ensures that the resulting JSON output is consistent. This allows you to commit the main.tf.json file to Git, just as you would with a main.tf file. Committing this file provides a safety net: if you refactor your Clojure code, Git will flag any unexpected changes in the main.tf.json file, giving you confidence in your refactoring process.
The deep-merge operation is essential in Terraform because it allows for the correct merging of attributes within blocks that share a namespace. This ensures that only the leaf nodes (individual attributes) are merged, preventing overwrites of entire nested structures.
(ns core (:require [big-config.utils :refer [deep-merge sort-nested-map]] [big-tofu.core :refer [add-suffix construct]] [big-tofu.create :as create] [cheshire.core :as json]))
(let [{:keys [aws-account-id region] :as data} {:aws-account-id "111111111111" :region "eu-west-1" :module "example"} queues (->> (for [n (range 2)] (create/sqs (add-suffix :alpha/big-sqs (str "-" n)))) flatten (map construct)) kms (->> (create/kms :alpha/big-kms) (map construct)) bucket (format "tf-state-%s-%s" aws-account-id region) provider (create/provider (assoc data :bucket bucket)) m (->> [provider] (into kms) (into queues) (apply deep-merge) sort-nested-map)] (json/generate-string m {:pretty true}))data "aws_caller_identity" "current" {}
data "aws_iam_policy_document" { alpha_big_kms_data_policy = { statement = { actions = ["kms:*"] effect = Allow principals = { identifiers = ["arn:aws:iam::${data.aws_caller_identity.current.account_id}:root"] type = AWS } resources = ["*"] } }}
provider "aws" { region = eu-west-1}
resource "aws_kms_key" "alpha_big_kms" {}
resource "aws_kms_key_policy" "alpha_big_kms_resource_policy" { key_id = resource.aws_kms_key.alpha_big_kms.id policy = data.aws_iam_policy_document.alpha_big_kms_data_policy.json}
resource "aws_sqs_queue" "alpha_big_sqs_0" { name = alpha_big_sqs_0}
resource "aws_sqs_queue" "alpha_big_sqs_1" { name = alpha_big_sqs_1}
terraform { backend "s3" { bucket = tf-state-111111111111-eu-west-1 encrypt = true key = example.tfstate region = eu-west-1 }
required_providers "aws" { source = hashicorp / aws version = "~> 5.0" } required_version = ">= 1.8.0"}{ "data" : { "aws_caller_identity" : { "current" : { } }, "aws_iam_policy_document" : { "alpha_big_kms_data_policy" : [ { "statement" : [ { "actions" : [ "kms:*" ], "effect" : "Allow", "principals" : [ { "identifiers" : [ "arn:aws:iam::${data.aws_caller_identity.current.account_id}:root" ], "type" : "AWS" } ], "resources" : [ "*" ] } ] } ] } }, "provider" : { "aws" : { "region" : "eu-west-1" } }, "resource" : { "aws_kms_key" : { "alpha_big_kms" : { } }, "aws_kms_key_policy" : { "alpha_big_kms_resource_policy" : { "key_id" : "${resource.aws_kms_key.alpha_big_kms.id}", "policy" : "${data.aws_iam_policy_document.alpha_big_kms_data_policy.json}" } }, "aws_sqs_queue" : { "alpha_big_sqs_0" : { "name" : "alpha_big_sqs_0" }, "alpha_big_sqs_1" : { "name" : "alpha_big_sqs_1" } } }, "terraform" : { "backend" : { "s3" : { "bucket" : "tf-state-111111111111-eu-west-1", "encrypt" : true, "key" : "example.tfstate", "region" : "eu-west-1" } }, "required_providers" : { "aws" : { "source" : "hashicorp/aws", "version" : "~> 5.0" } }, "required_version" : ">= 1.8.0" }}Account id
Section titled “Account id”It’s very common to get the AWS account id at runtime.
(construct caller-identity)data "aws_caller_identity" "current" {}(root-arn caller-identity)"arn:aws:iam::${data.aws_caller_identity.current.account_id}:root"Blocks
Section titled “Blocks”The defrecord Construct is used to construct any type of block. Naming is simplified by qualified keyword: ::foo becomes "org_app_foo::foo".
(ns org.app)(construct (map->Construct {:group :data :type :aws_iam_policy_document :fqn ::foo :block {}}))data "aws_iam_policy_document" "org_app_foo" {}Reference
Section titled “Reference”You can reference any property.
(ns org.app)(reference (map->Construct {:group :data :type :aws_iam_policy_document :fqn ::foo :block {}}) :json)data.aws_iam_policy_document.org_app_foo.jsonSome arn for common AWS resources are already defined.
Iam role
Section titled “Iam role”(arn (map->Construct {:group :resource :type :aws_iam_role :fqn ::foo :block {:name "name"}}) "111111111111")"arn:aws:iam::111111111111:role/name"Secret manager secret
Section titled “Secret manager secret”(arn (map->Construct {:group :resource :type :aws_secretsmanager_secret :fqn ::foo :block {:name "name"}}) "111111111111" "us-west-1")"arn:aws:secretsmanager:us-west-1:111111111111:secret/name"