Panfactum LogoPanfactum
Bootstrapping StackBootstrapping IaC

Bootstrapping Infrastructure-as-Code

Objective

Deploy your first modules using Terragrunt and OpenTofu (Terraform).

Set Up State Management

To begin deploying infrastructure, you will first need both a state backend and a way to encrypt configuration values.

We provide two infrastructure modules that define both those resources:

Deploying these modules for the first time is a bit cumbersome as they have circular references. 1

We provide a helper script pf-env-bootstrap that takes care of the initial setup automatically.

For every environment:

  1. Open its directory in your terminal (for example, <environments_dir>/production).

  2. Run pf-env-bootstrap.

  3. Confirm the prompt and wait for the bootstrap process to complete.

  4. Note that each environment now has tf_bootstrap_resources and sops (aws_kms_encrypt_key) deployed in its global region.

sops

Terragrunt uses sops to store secret configuration values. This allows you to commit secrets in encrypted form directly to version control which comes with a host of benefits:

  • All of your settings for all infrastructure can now be found in a single location.

  • You do not need a separate change management or CI/CD process for secrets and non-secret values.

  • You will implicitly have an audit log of all changes.

  • You can utilize sops for other git ops activities in addition to deploying infrastructure modules (e.g., performing automatic rotations).

The above bootstrapping process sets up sops to use AWS KMS for the encryption keys (via .sops.yaml). KMS provides several benefits:

  • sops uses transit encryption. As a result, the encryption keys never leave the key store. By using KMS, no one in your organization will ever have access to the encryption keys which means you do not need to rotate these keys (and thus all secrets encrypted with them) every time you offboard a member of your organization.

  • KMS allows you to replicate the encryption keys across multiple regions, ensuring you will never lose access.

  • KMS will provide an audit log for every time a secret value is accessed which will augment the git commit history that records every time a secret is changed.

  • Access to each KMS key will inherit our AWS role-based access control paradigm. As keys are scoped to each environment, access to secrets will automatically align with environment permissions. In other words, users with access to one environment will have access to that environment's secrets but not necessary secrets in other environments.

Let's perform a quick test to ensure sops is working properly.

  1. Create a new file at environments/management/test.yaml:

    foo: bar
    
  2. Run sops -e -i test.yaml ((e)ncrypt (i)n-place). The file contents should be transformed into something like the following:

    foo: ENC[AES256_GCM,data:JJWK,iv:iF2zywZM3DWObiJCPsaPzETwnlQ1q2lh+zgHfCmk/PM=,tag:m2Ii1IlH05fT/TE4SStWIA==,type:str]
    sops:
      kms:
        - arn: arn:aws:kms:us-east-2:143003111016:key/mrk-955687aaf5124a07837ae4e2a442f8ec
          created_at: "2024-03-08T17:27:00Z"
          enc: AQICAHgMz35tnCYOcZgsSkZfKep5SPbKOCK5kzijAQLnZXO3TAHQ6ctemzPMzRenMG2LWQjAAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQM4JXy9Gd99htGiu7aAgEQgDuxh107pk18bFU5Q8vzeu1rI+u6+/7s7Xao5DUSE/86Uyvo7USMny58KqJnqUdIvGmj3xYqV5dVMGJxAQ==
          aws_profile: management-superuser
        - arn: arn:aws:kms:us-west-2:143003111016:key/mrk-955687aaf5124a07837ae4e2a442f8ec
          created_at: "2024-03-08T17:27:00Z"
          enc: AQICAHgMz35tnCYOcZgsSkZfKep5SPbKOCK5kzijAQLnZXO3TAFwqRvjtwaFuBNp9ppYc58OAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMagf0c2ADsKLKXBFQAgEQgDsP5rqepGI3MvwhtRVxmS6/hyWWDyqEbOIxYS1WybNinBggkfKNRTw0Z8vob2tuSg5ZUeRpABry/C84PA==
          aws_profile: management-superuser
      gcp_kms: []
      azure_kv: []
      hc_vault: []
      age: []
      lastmodified: "2024-03-08T17:27:01Z"
      mac: ENC[AES256_GCM,data:JwzOMNKLn5ETSQY6QiGmxkxLqzX6buvs5OccPZ/BVOdfvgUW8vsgv34l6UiOidHq71GeGo5G9sPHeNiFGWPgqBMNU/qUugt9qldHs5k/oo6e4wFIzOxkIT2NZ1CmLw/9vxw8ZWskWX43XPC8tQlu9NmxE65G7NSDTaHBIFVVG44=,iv:L1pBiv+2y066RNr9qppBjuCjgLkaui6yOGJ6iPSCg8w=,tag:kmN5KBJ7gkhvcnkV67/xjw==,type:str]
      pgp: []
      unencrypted_suffix: _unencrypted
      version: 3.8.1
    

    This file is now safe to commit to version control.

  3. Run sops -d test.yaml ((d)ecrypt). Notice the original file contents should have been output to your terminal.

  4. Delete the file.

Deploy the AWS Account Module

Now that you have both the state backends and encryption keys established, we can start deploying infrastructure. The first resource will be the aws_account module. This module adds some critical metadata to your account including setting up its alias and contact information.

Let's deploy it now:

  1. In every environment's global region, create an aws_account directory.

  2. Add a terragrunt.hcl to the directory that looks like this.

    Note the addition of this line secrets = yamldecode(sops_decrypt_file("secrets.yaml")) which demonstrates how terragrunt and sops integrate with one another.

    Replace the values as needed for your organization. Feel free to also change what values are secret or not.

  3. Add a secrets.yaml to the directory:

    address_line_1: 1234 Platform Engineering Way
    city: Developer Junction
    district_or_county: Marion
    state_or_region: CA
    postal_code: "12345"
    phone_number: "+15555555555"
    email_address: spam@panfactum.com
    

    Adjust the values as necessary.

  4. Run sops -e -i secrets.yaml to encrypt the file.

  5. Run pf-tf-init in the module directory to enable the required providers.

  6. Run terragrunt apply in the module directory.

Next Steps

Now that you are set up to deploy infrastructure-as-code, we are ready to setup DNS.

PreviousNext
Panfactum Bootstrapping Guide:
Step 5 /20

Footnotes

  1. Deploying infrastructure modules requires a state backend, and the state backend is itself an infrastructure module.