<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Terrateam</title>
    <description>The latest articles on Forem by Terrateam (@terrateam-io).</description>
    <link>https://forem.com/terrateam-io</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1436579%2F1cbc9ab7-d58d-4ca2-a505-33f797d8421a.png</url>
      <title>Forem: Terrateam</title>
      <link>https://forem.com/terrateam-io</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/terrateam-io"/>
    <language>en</language>
    <item>
      <title>7 Best Terraform Cloud Alternatives for 2025</title>
      <dc:creator>Terrateam</dc:creator>
      <pubDate>Tue, 18 Mar 2025 22:27:31 +0000</pubDate>
      <link>https://forem.com/terrateam-io/7-best-terraform-cloud-alternatives-for-2025-58on</link>
      <guid>https://forem.com/terrateam-io/7-best-terraform-cloud-alternatives-for-2025-58on</guid>
      <description>&lt;h1&gt;
  
  
  7 Best Terraform Cloud Alternatives for 2025
&lt;/h1&gt;

&lt;p&gt;HashiCorp's pricing model change has prompted organizations to look for alternatives to Terraform Cloud. Several powerful options have emerged, offering cost predictability and control over infrastructure automation, extending beyond basic Terraform use.&lt;/p&gt;

&lt;p&gt;Modern DevOps teams need tools that save costs, provide reliable state management, smooth CI/CD integration, and policy enforcement. The right tool can improve productivity and resource effectiveness.&lt;/p&gt;

&lt;p&gt;This article reviews seven Terraform Cloud alternatives, focusing on deployment models, operational needs, and integration features. Each tool’s strengths help you choose the best fit for your organization's requirements.&lt;/p&gt;

&lt;h2&gt;
  
  
  Factors in Selecting Alternatives
&lt;/h2&gt;

&lt;p&gt;Evaluate tools by looking at deployment models, operational needs, and integration features. Self-hosted options offer more control and security but require existing infrastructure management skills and data sovereignty requirements. SaaS solutions provide quick deployment and reduce operational overhead.&lt;/p&gt;

&lt;p&gt;Key features to consider are state management, workspace organization, and CI/CD integration. Reliable state locking and versioning are important. Supporting multiple environments and team structures impacts operational success. Tools should support automated plan generation and apply operations and drift detection within CI/CD pipelines. GitOps lets teams manage infrastructure changes through pull requests, facilitating code review and maintaining a change audit trail.&lt;/p&gt;

&lt;h2&gt;
  
  
  Alternatives for Infrastructure Automation
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Terrateam: GitOps-First Terraform Automation
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/terrateamio/terrateam" rel="noopener noreferrer"&gt;Terrateam&lt;/a&gt; is a GitOps-first alternative to Terraform Cloud, built for teams automating infrastructure in GitHub. It integrates directly with pull request workflows, enforcing code reviews and automating Terraform, OpenTofu, Pulumi, CDKTF, and more. Everything runs within GitHub without requiring an external UI, keeping your workflow simple and secure. State files remain within your infrastructure, and advanced workflow features support complex, multi-step deployments. For teams using GitHub, Terrateam provides a lightweight and scalable alternative without the complexity of extra tooling.&lt;/p&gt;

&lt;h3&gt;
  
  
  Atlantis: Open-Source Self-Hosted GitOps
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://www.runatlantis.io/" rel="noopener noreferrer"&gt;Atlantis&lt;/a&gt; automates Terraform workflows through pull requests, maintaining clear audit trails. It integrates with Git repositories, offering a standardized workflow for reviewing and applying changes. Its self-hosted nature requires ongoing maintenance.&lt;/p&gt;

&lt;h3&gt;
  
  
  Terrakube: 100% Open-Source Platform
&lt;/h3&gt;

&lt;p&gt;Terrakube provides a solution with private registry support and custom workflows, integrating with major VCS systems and allowing extensive customization. It suits teams wanting full control over infrastructure management. Recent updates include workspace importers for Terraform Cloud migrations and OpenTofu integration.&lt;/p&gt;

&lt;h3&gt;
  
  
  Burrito: Lightweight GitOps Automation
&lt;/h3&gt;

&lt;p&gt;Burrito manages Terraform code through CI/CD pipelines. Its lightweight nature and GitOps alignment suit teams wanting simple workflows with effective drift detection. Burrito runs within infrastructure, providing security and control over operations.&lt;/p&gt;

&lt;h3&gt;
  
  
  Airplane: Infrastructure Automation with Terraform
&lt;/h3&gt;

&lt;p&gt;Airplane enhances Terraform's workflow capabilities with integration and automation features. It uses CI/CD pipelines and tool integration to automate deployments efficiently, making it suitable for teams needing reliable infrastructure.&lt;/p&gt;

&lt;h3&gt;
  
  
  Teller: Secrets Management and Automation
&lt;/h3&gt;

&lt;p&gt;Teller manages secrets and integrates seamlessly with Terraform automation, securely managing sensitive information and ensuring real-time secret population. It supports CI/CD integration, detecting secret drift before deployment, maintaining secure and efficient process.&lt;/p&gt;

&lt;h3&gt;
  
  
  EnvZilla: Open-Source Environment Automation
&lt;/h3&gt;

&lt;p&gt;EnvZilla, though not widely documented, aligns with automation needs by promoting environment management and streamlining workflows for Terraform configurations. Its features and integrations are comparable with other discussed alternatives.&lt;/p&gt;

&lt;h2&gt;
  
  
  Selecting the Right Tool
&lt;/h2&gt;

&lt;p&gt;Your choice depends on specific needs and constraints. Teams focused on GitHub integration might prefer Terrateam or Atlantis. Organizations requiring enterprise features and multi-framework support might find Airplane or Terrakube advantageous. If cost control is a priority, select a solution with comprehensive cost estimation and policy integration.&lt;/p&gt;

&lt;p&gt;Start by assessing core requirements like state management, policy enforcement, and collaboration features. Test chosen solutions in controlled environments for compatibility with workflows. Successful implementation depends on setup and team adoption, so invest in training and establishing clear infrastructure automation processes.&lt;/p&gt;

</description>
      <category>terraform</category>
      <category>devops</category>
      <category>infrastructureascode</category>
    </item>
    <item>
      <title>Deploying an AWS EKS Cluster with Terraform and GitHub Actions</title>
      <dc:creator>Terrateam</dc:creator>
      <pubDate>Tue, 11 Mar 2025 19:58:22 +0000</pubDate>
      <link>https://forem.com/terrateam/deploying-an-aws-eks-cluster-with-terraform-and-github-actions-g01</link>
      <guid>https://forem.com/terrateam/deploying-an-aws-eks-cluster-with-terraform-and-github-actions-g01</guid>
      <description>&lt;p&gt;This guide shows you how to automate EKS cluster deployment using Terraform and GitHub Actions. You'll learn to create a production-ready Kubernetes environment with networking, security, and scaling capabilities.&lt;/p&gt;

&lt;h2&gt;
  
  
  VPC and Network Architecture
&lt;/h2&gt;

&lt;p&gt;Create a dedicated VPC for the cluster.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_vpc"&lt;/span&gt; &lt;span class="s2"&gt;"eks_vpc"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;cidr_block&lt;/span&gt;           &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"10.0.0.0/16"&lt;/span&gt;
  &lt;span class="nx"&gt;enable_dns_hostnames&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="nx"&gt;enable_dns_support&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

  &lt;span class="nx"&gt;tags&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"eks-vpc"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_subnet"&lt;/span&gt; &lt;span class="s2"&gt;"private"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;count&lt;/span&gt;             &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
  &lt;span class="nx"&gt;vpc_id&lt;/span&gt;            &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_vpc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;eks_vpc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
  &lt;span class="nx"&gt;cidr_block&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"10.0.${count.index + 1}.0/24"&lt;/span&gt;
  &lt;span class="nx"&gt;availability_zone&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;aws_availability_zones&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;available&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;names&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

  &lt;span class="nx"&gt;tags&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;Name&lt;/span&gt;                              &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"eks-private-${count.index + 1}"&lt;/span&gt;
    &lt;span class="s2"&gt;"kubernetes.io/role/internal-elb"&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"1"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Private subnets host the worker nodes while public subnets handle incoming traffic through load balancers. The subnet tags enable automatic discovery by Kubernetes for internal load balancer placement.&lt;/p&gt;

&lt;h2&gt;
  
  
  EKS Cluster and Node Groups
&lt;/h2&gt;

&lt;p&gt;The EKS cluster consists of a control plane for managing Kubernetes components and worker nodes for running workloads:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_eks_cluster"&lt;/span&gt; &lt;span class="s2"&gt;"main"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"eks-cluster"&lt;/span&gt;
  &lt;span class="nx"&gt;role_arn&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_iam_role&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;eks_cluster&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;arn&lt;/span&gt;
  &lt;span class="nx"&gt;version&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"1.27"&lt;/span&gt;

  &lt;span class="nx"&gt;vpc_config&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;subnet_ids&lt;/span&gt;              &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_subnet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;private&lt;/span&gt;&lt;span class="p"&gt;[*].&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
    &lt;span class="nx"&gt;endpoint_private_access&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="nx"&gt;endpoint_public_access&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;depends_on&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nx"&gt;aws_iam_role_policy_attachment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;eks_cluster_policy&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_eks_node_group"&lt;/span&gt; &lt;span class="s2"&gt;"main"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;cluster_name&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_eks_cluster&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;
  &lt;span class="nx"&gt;node_group_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"eks-node-group"&lt;/span&gt;
  &lt;span class="nx"&gt;node_role_arn&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_iam_role&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;eks_nodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;arn&lt;/span&gt;
  &lt;span class="nx"&gt;subnet_ids&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_subnet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;private&lt;/span&gt;&lt;span class="p"&gt;[*].&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;

  &lt;span class="nx"&gt;scaling_config&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;desired_size&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
    &lt;span class="nx"&gt;max_size&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;
    &lt;span class="nx"&gt;min_size&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;instance_types&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"t3.medium"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;a href="https://aws.amazon.com/blogs/containers/bootstrapping-clusters-with-eks-blueprints/" rel="noopener noreferrer"&gt;EKS Blueprints for Terraform&lt;/a&gt; provide production-ready modules to accelerate cluster deployment. Breaking the configuration into modules improves maintainability:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt; &lt;span class="s2"&gt;"vpc"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;source&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"./modules/vpc"&lt;/span&gt;
  &lt;span class="c1"&gt;# VPC configuration parameters&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt; &lt;span class="s2"&gt;"eks"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;source&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"./modules/eks"&lt;/span&gt;
  &lt;span class="c1"&gt;# EKS configuration parameters&lt;/span&gt;
  &lt;span class="nx"&gt;vpc_id&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vpc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vpc_id&lt;/span&gt;
  &lt;span class="nx"&gt;subnet_ids&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vpc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;private_subnet_ids&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Automating Deployments with GitHub Actions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Workflow File
&lt;/h3&gt;

&lt;p&gt;Create a workflow file in &lt;code&gt;.github/workflows&lt;/code&gt; to define the deployment process:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Terraform AWS Workflow&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;main&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;main&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;terraform&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;permissions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;id-token&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;write&lt;/span&gt;
      &lt;span class="na"&gt;contents&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;read&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v3&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Configure AWS Credentials&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws-actions/configure-aws-credentials@v2&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;role-to-assume&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;arn:aws:iam::123456789012:role/github-actions&lt;/span&gt;
          &lt;span class="na"&gt;aws-region&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;us-west-2&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Setup Terraform&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hashicorp/setup-terraform@v3&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Terraform Init&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;terraform init&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Terraform Plan&lt;/span&gt;
        &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;github.event_name == 'pull_request'&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;terraform plan -no-color&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Terraform Apply&lt;/span&gt;
        &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;github.ref == 'refs/heads/main' &amp;amp;&amp;amp; github.event_name == 'push'&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;terraform apply -auto-approve&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  State Management
&lt;/h3&gt;

&lt;p&gt;Store Terraform state in S3.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;terraform&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;backend&lt;/span&gt; &lt;span class="s2"&gt;"s3"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;bucket&lt;/span&gt;         &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"terraform-state-bucket"&lt;/span&gt;
    &lt;span class="nx"&gt;key&lt;/span&gt;            &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"eks/terraform.tfstate"&lt;/span&gt;
    &lt;span class="nx"&gt;region&lt;/span&gt;         &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"us-west-2"&lt;/span&gt;
    &lt;span class="nx"&gt;dynamodb_table&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"terraform-state-lock"&lt;/span&gt;
    &lt;span class="nx"&gt;encrypt&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="nx"&gt;use_lockfile&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Managing Production
&lt;/h2&gt;

&lt;h3&gt;
  
  
  GitOps and Add-on Management
&lt;/h3&gt;

&lt;p&gt;Deploy ArgoCD using the EKS Blueprints framework:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt; &lt;span class="s2"&gt;"kubernetes_addons"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;source&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"github.com/aws-ia/terraform-aws-eks-blueprints//modules/kubernetes-addons"&lt;/span&gt;

  &lt;span class="nx"&gt;eks_cluster_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;eks_blueprints&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;eks_cluster_id&lt;/span&gt;

  &lt;span class="nx"&gt;enable_argocd&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="nx"&gt;enable_metrics_server&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="nx"&gt;enable_cluster_autoscaler&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="nx"&gt;enable_aws_load_balancer_controller&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

  &lt;span class="nx"&gt;argocd_helm_config&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;values&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;templatefile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"${path.module}/values.yaml"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{})]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Monitoring and Scaling
&lt;/h3&gt;

&lt;p&gt;Implement automatic scaling based on resource utilization:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_autoscaling_policy"&lt;/span&gt; &lt;span class="s2"&gt;"cluster_autoscaling"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"eks-cluster-autoscaling"&lt;/span&gt;
  &lt;span class="nx"&gt;policy_type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"TargetTrackingScaling"&lt;/span&gt;
  &lt;span class="nx"&gt;target_tracking_configuration&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;target_value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;75.0&lt;/span&gt;
    &lt;span class="nx"&gt;predefined_metric_specification&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;predefined_metric_type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"ASGAverageCPUUtilization"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;autoscaling_group_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_eks_node_group&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resources&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;autoscaling_groups&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Next Steps
&lt;/h2&gt;

&lt;p&gt;Automating EKS with GitHub Actions is a reliable way to manage your new cluster. For teams looking to improve their infrastructure workflows, check out &lt;a href="https://github.com/terrateamio/terrateam" rel="noopener noreferrer"&gt;Terrateam (OSS)&lt;/a&gt; which provides a GitOps-first approach to managing Terraform in GitHub.&lt;/p&gt;

</description>
      <category>terraform</category>
      <category>github</category>
      <category>eks</category>
      <category>kubernetes</category>
    </item>
    <item>
      <title>Building a CI/CD Pipeline for Terraform with GitHub Actions (Step-by-Step Guide)</title>
      <dc:creator>Terrateam</dc:creator>
      <pubDate>Thu, 06 Mar 2025 19:24:09 +0000</pubDate>
      <link>https://forem.com/terrateam/building-a-cicd-pipeline-for-terraform-with-github-actions-step-by-step-guide-3dlp</link>
      <guid>https://forem.com/terrateam/building-a-cicd-pipeline-for-terraform-with-github-actions-step-by-step-guide-3dlp</guid>
      <description>&lt;p&gt;Manual Terraform operations are slow and create bottlenecks. Each deployment requires careful coordination and multiple operations. Automating these operations through a CI/CD pipeline streamlines this tedious process. Research from HashiCorp shows that organizations using automated Terraform workflows deploy infrastructure changes 89% faster than those relying on manual processes.&lt;/p&gt;

&lt;p&gt;This guide shows you how to build a CI/CD pipeline using GitHub Actions to automate your Terraform operations. You'll learn how to set up secure authentication with AWS using OpenID Connect (OIDC), manage remote state, and create workflows that automatically validate and apply infrastructure changes. By the end, you'll have a production-ready pipeline that runs format checks and plans on pull requests, then applies changes automatically when code merges to main.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up the Foundation
&lt;/h2&gt;

&lt;p&gt;Before building your pipeline, you need a GitHub repository for your Terraform configurations and an AWS account for deploying resources. Your repository should follow infrastructure-as-code best practices with clear documentation and structured Terraform files.&lt;/p&gt;

&lt;h3&gt;
  
  
  Remote State Management
&lt;/h3&gt;

&lt;p&gt;Teams need a reliable system to store and manage Terraform state files. &lt;a href="https://developer.hashicorp.com/terraform/language/settings/backends/s3" rel="noopener noreferrer"&gt;AWS S3&lt;/a&gt; provides remote state storage and locking to prevent concurrent modifications. Configure your system in your Terraform configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;terraform&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;backend&lt;/span&gt; &lt;span class="s2"&gt;"s3"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;bucket&lt;/span&gt;         &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"your-terraform-state-bucket"&lt;/span&gt;
    &lt;span class="nx"&gt;key&lt;/span&gt;            &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"terraform.tfstate"&lt;/span&gt;
    &lt;span class="nx"&gt;region&lt;/span&gt;         &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"us-west-2"&lt;/span&gt;
    &lt;span class="nx"&gt;use_lockfile&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="nx"&gt;encrypt&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Secure AWS Authentication
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/configuring-openid-connect-in-amazon-web-services" rel="noopener noreferrer"&gt;OpenID Connect (OIDC)&lt;/a&gt; eliminates the need for storing long-lived AWS credentials in GitHub. GitHub Actions generates short-lived tokens to assume AWS roles, reducing security risks and simplifying credential management.&lt;/p&gt;

&lt;p&gt;To set up OIDC:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create an OIDC provider in AWS IAM using the address &lt;code&gt;https://token.actions.githubusercontent.com&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Create an IAM role with this trust policy:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2012-10-17"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Statement"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Principal"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"Federated"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:iam::ACCOUNT-ID:oidc-provider/token.actions.githubusercontent.com"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"sts:AssumeRoleWithWebIdentity"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Condition"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"StringLike"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"token.actions.githubusercontent.com:sub"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"repo:organization/repository:*"&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Creating GitHub Actions Workflows
&lt;/h2&gt;

&lt;p&gt;GitHub Actions uses YAML files in the &lt;code&gt;.github/workflows&lt;/code&gt; directory to define CI/CD pipelines. Two workflows are going to be created: one for pull request validation and another for applying changes to production.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pull Request Validation
&lt;/h3&gt;

&lt;p&gt;Create &lt;code&gt;terraform-plan.yml&lt;/code&gt; to run whenever a pull request is created or updated:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Terraform&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Plan'&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;terraform&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;permissions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;contents&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;read&lt;/span&gt;
      &lt;span class="na"&gt;pull-requests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;write&lt;/span&gt;
      &lt;span class="na"&gt;id-token&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;write&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Configure AWS Credentials&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws-actions/configure-aws-credentials@v2&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;role-to-assume&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.AWS_ROLE_ARN }}&lt;/span&gt;
          &lt;span class="na"&gt;aws-region&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;us-west-2&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Setup Terraform&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hashicorp/setup-terraform@v1&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Terraform Init&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;terraform init&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Terraform Format&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;terraform fmt -check&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Terraform Plan&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;terraform plan -out=tfplan&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Add Plan Comment&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/github-script@v6&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;github-token&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.GITHUB_TOKEN }}&lt;/span&gt;
          &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
            &lt;span class="s"&gt;const output = `#### Terraform Plan Output&lt;/span&gt;
            &lt;span class="s"&gt;\`\`\`&lt;/span&gt;
            &lt;span class="s"&gt;${process.env.PLAN_OUTPUT}&lt;/span&gt;
            &lt;span class="s"&gt;\`\`\`&lt;/span&gt;
            &lt;span class="s"&gt;`;&lt;/span&gt;
            &lt;span class="s"&gt;github.rest.issues.createComment({&lt;/span&gt;
              &lt;span class="s"&gt;issue_number: context.issue.number,&lt;/span&gt;
              &lt;span class="s"&gt;owner: context.repo.owner,&lt;/span&gt;
              &lt;span class="s"&gt;repo: context.repo.repo,&lt;/span&gt;
              &lt;span class="s"&gt;body: output&lt;/span&gt;
            &lt;span class="s"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Production Deployment
&lt;/h3&gt;

&lt;p&gt;Create &lt;code&gt;terraform-apply.yml&lt;/code&gt; to run when changes merge to main:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Terraform&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Apply'&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;main&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;terraform&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;permissions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;contents&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;read&lt;/span&gt;
      &lt;span class="na"&gt;id-token&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;write&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Configure AWS Credentials&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws-actions/configure-aws-credentials@v2&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;role-to-assume&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.AWS_ROLE_ARN }}&lt;/span&gt;
          &lt;span class="na"&gt;aws-region&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;us-west-2&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Setup Terraform&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hashicorp/setup-terraform@v1&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Terraform Init&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;terraform init&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Terraform Apply&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;terraform apply -auto-approve&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Improving the Pipeline
&lt;/h2&gt;

&lt;p&gt;Add these features to improve your pipeline's functionality and visibility:&lt;/p&gt;

&lt;h3&gt;
  
  
  Status Badges
&lt;/h3&gt;

&lt;p&gt;Add this badge to your README.md to show pipeline status:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;![&lt;/span&gt;&lt;span class="nv"&gt;Terraform CI&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;https://github.com/{owner}/{repo}/actions/workflows/{workflow-name}/badge.svg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Plan Output Comments
&lt;/h3&gt;

&lt;p&gt;The workflow automatically posts Terraform plan outputs as comments on pull requests. This helps reviewers understand proposed changes without leaving the PR interface. The plan output uses formatted code blocks for readability and includes resource changes, additions, and deletions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Automating with Confidence
&lt;/h2&gt;

&lt;p&gt;A well-configured Terraform pipeline with GitHub Actions transforms infrastructure deployment from a manual process into a streamlined workflow. GitHub Actions' features enable teams to test across multiple environments and use specialized runners for complex deployments. The combination of OIDC authentication, remote state management, and automated plan reviews creates a secure and efficient process that reduces deployment time while maintaining high standards for infrastructure changes. &lt;/p&gt;

&lt;p&gt;In addition, integrating open-source solutions like &lt;a href="https://github.com/terrateamio/terrateam" rel="noopener noreferrer"&gt;Terrateam&lt;/a&gt; can further improve your Terraform and GitHub workflows. Terrateam offers automated deployments, customized workflows, and features that strengthen security and compliance, making infrastructure management even more effective.&lt;/p&gt;

</description>
      <category>terraform</category>
      <category>devops</category>
      <category>github</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Migrating from Terraform to OpenTofu</title>
      <dc:creator>Terrateam</dc:creator>
      <pubDate>Thu, 06 Feb 2025 19:50:48 +0000</pubDate>
      <link>https://forem.com/terrateam/migrating-from-terraform-to-opentofu-1jdo</link>
      <guid>https://forem.com/terrateam/migrating-from-terraform-to-opentofu-1jdo</guid>
      <description>&lt;p&gt;OpenTofu maintains the core functionality that made Terraform successful while introducing important improvements. The project operates under community governance, ensuring features and fixes align with the community. All of the Terraform providers worked with OpenTofu with the &lt;a href="https://github.com/opentofu/registry" rel="noopener noreferrer"&gt;OpenTofu registry&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Executing the Migration
&lt;/h2&gt;

&lt;p&gt;The migration to OpenTofu is a straightforward process:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Install OpenTofu using your preferred package manager or download the binary from the &lt;a href="https://github.com/opentofu/opentofu/releases" rel="noopener noreferrer"&gt;OpenTofu releases page&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Update your scripts and CI/CD configurations to use the &lt;code&gt;tofu&lt;/code&gt; command instead of &lt;code&gt;terraform&lt;/code&gt;:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Before&lt;/span&gt;
terraform init
terraform plan
terraform apply

&lt;span class="c"&gt;# After&lt;/span&gt;
tofu init
tofu plan
tofu apply
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For teams using &lt;a href="https://github.com/terrateamio/terrateam" rel="noopener noreferrer"&gt;Terrateam&lt;/a&gt;, update your &lt;code&gt;.terrateam/config.yml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;engine&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;tofu&lt;/span&gt;
  &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1.9.0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This configuration ensures &lt;a href="https://docs.terrateam.io/integrations/opentofu/" rel="noopener noreferrer"&gt;Terrateam uses OpenTofu&lt;/a&gt; for all operations while maintaining your existing GitOps workflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building for the Future
&lt;/h2&gt;

&lt;p&gt;OpenTofu is more than just an alternative to Terraform. It brings the principles of open-source software and community-driven progress to infrastructure as code. The migration process is very simple to do and it's also possible to migrate back to Terraform. The long-term benefits of an open-source solution make OpenTofu a worthwhile investment for organizations committed to infrastructure as code.&lt;/p&gt;

</description>
      <category>terraform</category>
      <category>infrastructureascode</category>
      <category>devops</category>
      <category>opensource</category>
    </item>
    <item>
      <title>5 Open Source Repositories to Level Up Your GitOps</title>
      <dc:creator>Terrateam</dc:creator>
      <pubDate>Wed, 05 Feb 2025 15:57:03 +0000</pubDate>
      <link>https://forem.com/terrateam/5-open-source-repositories-to-level-up-your-gitops-33np</link>
      <guid>https://forem.com/terrateam/5-open-source-repositories-to-level-up-your-gitops-33np</guid>
      <description>&lt;p&gt;Version controlling your infrastructure is a starting point. The real power comes from automating the deployment pipeline. Teams using GitOps deploy faster and recover from downtime and incidents faster, but this requires the right tools.&lt;/p&gt;

&lt;p&gt;Git provides the foundation for GitOps, but teams need specialized tools to put it into practice. This article highlights five open-source projects that help with different parts of a GitOps workflow: feature management, infrastructure automation, and database migrations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Flagsmith: Feature Flags
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/Flagsmith/flagsmith" rel="noopener noreferrer"&gt;Flagsmith&lt;/a&gt; lets teams manage feature flags, and it integrates with GitOps workflows using Terraform. Feature flags can be stored in Git, ensuring changes go through the same review process as infrastructure updates.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;flagsmith&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Flagsmith&lt;/span&gt;

&lt;span class="n"&gt;flagsmith&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Flagsmith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;environment_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;your_key&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;default_flag_handler&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Fetch and embed flag states at runtime
&lt;/span&gt;&lt;span class="n"&gt;flags&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;flagsmith&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_environment_flags&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In a GitOps setup, feature flags should be stored in Git and deployed alongside other code changes. Teams can enforce flag updates only when a corresponding application version is deployed. CI/CD pipelines (e.g., GitHub Actions, GitLab CI, or Terrateam) handle these updates.&lt;/p&gt;

&lt;p&gt;With GitOps, every feature flag change is tracked in Git, making it easy to see what changed and roll back if needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Terrateam: Infrastructure Automation
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/terrateamio/terrateam" rel="noopener noreferrer"&gt;Terrateam&lt;/a&gt; integrates Terraform and OpenTofu directly into pull request workflows. It validates infrastructure changes before merging and applies them after approval.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;workflows&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;tag_query&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;dir:infrastructure/staging"&lt;/span&gt;
    &lt;span class="na"&gt;plan&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;env&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TF_VAR_example&lt;/span&gt;
        &lt;span class="na"&gt;cmd&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;echo"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Set&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;custom&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;environment&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;variable"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;init&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;plan&lt;/span&gt;
    &lt;span class="na"&gt;apply&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;run&lt;/span&gt;
        &lt;span class="na"&gt;cmd&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;echo"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Running&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;custom&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;apply&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;script"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;init&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apply&lt;/span&gt;

&lt;span class="na"&gt;parallel_runs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;

&lt;span class="na"&gt;cost_estimation&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Terrateam integrates with GitHub Actions and Secrets, providing plan outputs and cost estimates directly in pull requests. It ensures ordered execution to prevent dependency-related failures and maintains a full audit trail of infrastructure changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  ArgoCD: Kubernetes Deployment
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/argoproj/argo-cd" rel="noopener noreferrer"&gt;ArgoCD&lt;/a&gt; brings GitOps to Kubernetes by continuously monitoring and syncing cluster states with Git.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;argoproj.io/v1alpha1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Application&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;guestbook&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;argocd&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;project&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;default&lt;/span&gt;
  &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;repoURL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://github.com/argoproj/argocd-example-apps.git&lt;/span&gt;
    &lt;span class="na"&gt;targetRevision&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;HEAD&lt;/span&gt;
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;guestbook&lt;/span&gt;
  &lt;span class="na"&gt;destination&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;server&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://kubernetes.default.svc&lt;/span&gt;
    &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;guestbook&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ArgoCD helps maintain the desired state, with configurable sync policies. It supports PreSync, Sync, and PostSync hooks for deployment changes and allows rollbacks.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Sync an application&lt;/span&gt;
argocd app &lt;span class="nb"&gt;sync &lt;/span&gt;guestbook

&lt;span class="c"&gt;# Rollback to a previous version&lt;/span&gt;
argocd app rollback guestbook
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  FluxCD: Kubernetes Reconciliation
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://fluxcd.io" rel="noopener noreferrer"&gt;FluxCD&lt;/a&gt; runs as a Kubernetes controller, reconciling Git repositories with cluster states. It follows a pull-based model and scales across multiple clusters.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;source.toolkit.fluxcd.io/v1beta2&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;GitRepository&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;app-repository&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;flux-system&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;interval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1m&lt;/span&gt;
  &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://github.com/org/repository&lt;/span&gt;
  &lt;span class="na"&gt;ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;main&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;FluxCD supports multi-tenant deployments using Kubernetes namespaces and Role-Based Access Control. It integrates with Helm and Kustomize.&lt;/p&gt;

&lt;h2&gt;
  
  
  Atlas: Database Schema Management
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/ariga/atlas" rel="noopener noreferrer"&gt;Atlas&lt;/a&gt; manages database schema changes in GitOps workflows using declarative schema definitions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;table&lt;/span&gt; &lt;span class="s2"&gt;"users"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;schema&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;
  &lt;span class="nx"&gt;column&lt;/span&gt; &lt;span class="s2"&gt;"id"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;int&lt;/span&gt;
    &lt;span class="nx"&gt;auto_increment&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;column&lt;/span&gt; &lt;span class="s2"&gt;"name"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;primary_key&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;columns&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;column&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Atlas integrates with CI/CD pipelines for schema validation and migration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;atlas migrate diff &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--dir&lt;/span&gt; &lt;span class="s2"&gt;"file://migrations"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--to&lt;/span&gt; &lt;span class="s2"&gt;"file://schema.hcl"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"add_users_table"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Building a Complete GitOps Pipeline
&lt;/h2&gt;

&lt;p&gt;These tools work together to create a full GitOps pipeline. &lt;a href="https://github.com/Flagsmith/flagsmith" rel="noopener noreferrer"&gt;Flagsmith&lt;/a&gt; manages feature releases via Terraform, while &lt;a href="https://github.com/terrateamio/terrateam" rel="noopener noreferrer"&gt;Terrateam&lt;/a&gt; handles infrastructure changes directly through GitHub (and possibly GitLab in the future). &lt;a href="https://github.com/argoproj/argo-cd" rel="noopener noreferrer"&gt;ArgoCD&lt;/a&gt; and &lt;a href="https://github.com/fluxcd/flux2" rel="noopener noreferrer"&gt;FluxCD&lt;/a&gt; ensure reliable application deployments via Kubernetes, and &lt;a href="https://github.com/ariga/atlas" rel="noopener noreferrer"&gt;Atlas&lt;/a&gt; integrates database schema migrations.&lt;/p&gt;

&lt;p&gt;These tools help you build automated, secure, and scalable GitOps pipelines. They're open-source, shaped by real-world usage and community contributions.&lt;/p&gt;

&lt;p&gt;If these tools make your life easier, drop them a star on GitHub!&lt;/p&gt;

</description>
      <category>gitops</category>
      <category>devops</category>
      <category>featureflags</category>
      <category>kubernetes</category>
    </item>
    <item>
      <title>Using GitHub Secrets with Terraform</title>
      <dc:creator>Terrateam</dc:creator>
      <pubDate>Tue, 04 Feb 2025 14:18:21 +0000</pubDate>
      <link>https://forem.com/terrateam-io/using-github-secrets-with-terraform-195i</link>
      <guid>https://forem.com/terrateam-io/using-github-secrets-with-terraform-195i</guid>
      <description>&lt;h2&gt;
  
  
  Protecting Terraform Secrets in GitHub Actions
&lt;/h2&gt;

&lt;p&gt;GitHub Actions offers built-in secrets management that works well with Terraform deployments. This article shows you how to set up GitHub Actions for Terraform, store sensitive data securely, and use these secrets in your infrastructure code. You'll learn practical techniques to keep your automation pipelines running while protecting your credentials from exposure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up GitHub Actions for Terraform
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://github.com/hashicorp/setup-terraform" rel="noopener noreferrer"&gt;hashicorp/setup-terraform action&lt;/a&gt; enables Terraform automation within GitHub Actions pipelines. Create a new workflow file in &lt;code&gt;.github/workflows&lt;/code&gt; to run Terraform operations on pull requests and pushes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Terraform&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;CI'&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;main&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;main&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;terraform&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v3&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hashicorp/setup-terraform@v3&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Terraform Init&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;terraform init&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Terraform Plan&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;terraform plan&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Managing Secrets in GitHub Actions
&lt;/h2&gt;

&lt;p&gt;GitHub Actions encrypts sensitive information at rest and ensures secrets remain inaccessible outside of workflows. To add secrets to your repository:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to your repository's Settings&lt;/li&gt;
&lt;li&gt;Select "Secrets and variables" under "Security"&lt;/li&gt;
&lt;li&gt;Click "New repository secret"&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Reference these secrets in your workflow using the secrets context:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Terraform Plan&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;terraform&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v3&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hashicorp/setup-terraform@v3&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Terraform Init&lt;/span&gt;
        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;TF_VAR_api_token&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.API_TOKEN }}&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;terraform init&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;GitHub Actions automatically redacts secret values from logs and blocks access from untrusted forks or pull requests. The secrets context (&lt;code&gt;${{ secrets.SECRET_NAME }}&lt;/code&gt;) ensures sensitive values remain protected during workflow execution.&lt;/p&gt;

&lt;h2&gt;
  
  
  Integrating Secrets with Terraform Code
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://developer.hashicorp.com/terraform/language/state/sensitive-data" rel="noopener noreferrer"&gt;Terraform state files store all configuration values&lt;/a&gt;, including secrets, in plaintext by default. Use the &lt;code&gt;sensitive&lt;/code&gt; attribute to prevent accidental exposure in logs and outputs, but always use a secure backend (e.g. AWS S3 with encryption) to store state safely.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"api_token"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
  &lt;span class="nx"&gt;sensitive&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"API token for authentication"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;provider&lt;/span&gt; &lt;span class="s2"&gt;"aws"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;region&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"us-west-2"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For database credentials and other sensitive data:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"database_password"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
  &lt;span class="nx"&gt;sensitive&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Password for database access"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_db_instance"&lt;/span&gt; &lt;span class="s2"&gt;"example"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;password&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;database_password&lt;/span&gt;
  &lt;span class="c1"&gt;# Additional configuration...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;AWS credentials should &lt;strong&gt;never&lt;/strong&gt; be stored in Terraform variables. Instead, use IAM roles, AWS profiles, or environment variables (&lt;code&gt;AWS_ACCESS_KEY_ID&lt;/code&gt;, &lt;code&gt;AWS_SECRET_ACCESS_KEY&lt;/code&gt;) to authenticate securely.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building Secure Infrastructure Automation
&lt;/h2&gt;

&lt;p&gt;Proper secrets management isn't optional: it's a fundamental requirement for infrastructure automation. GitHub Actions' secrets management combined with Terraform's security features creates a strong framework for protecting sensitive data throughout the deployment pipeline.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/terrateamio/terrateam" rel="noopener noreferrer"&gt;Terrateam&lt;/a&gt; extends these capabilities with automated planning, cost estimation, and environment-specific policies. By implementing these practices and tools, teams can automate infrastructure deployments without compromising security. The result is a deployment pipeline that moves fast while keeping credentials locked down.&lt;/p&gt;

</description>
      <category>terraform</category>
      <category>devops</category>
      <category>infrastructureascode</category>
      <category>github</category>
    </item>
    <item>
      <title>OpenTofu Feature Preview: State Encryption</title>
      <dc:creator>Terrateam</dc:creator>
      <pubDate>Fri, 19 Apr 2024 14:48:09 +0000</pubDate>
      <link>https://forem.com/terrateam-io/opentofu-feature-preview-state-encryption-3h8e</link>
      <guid>https://forem.com/terrateam-io/opentofu-feature-preview-state-encryption-3h8e</guid>
      <description>&lt;h2&gt;
  
  
  Background
&lt;/h2&gt;

&lt;p&gt;The original &lt;a href="https://github.com/hashicorp/terraform/issues/9556" rel="noopener noreferrer"&gt;proposal&lt;/a&gt; for Terraform state encryption was created back in 2016 in the &lt;code&gt;hashicorp/terraform&lt;/code&gt; repository. It was created by one of the core project maintainers. The Issue has been stale for years and there's even been an ignored &lt;a href="https://github.com/hashicorp/terraform/pull/28603" rel="noopener noreferrer"&gt;pull request&lt;/a&gt; to implement the feature request.&lt;/p&gt;

&lt;p&gt;It's clear that this feature request does not align with the HashiCorp roadmap and that they are ignoring the community. Odd considering the fact that they could easily use state encryption as an upsell and tie it into their Vault offering.&lt;/p&gt;

&lt;p&gt;One can only speculate why this feature request has been ignored. Perhaps they don't think state encryption is important to a security story or that they think encryption at-rest is sufficient.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In this blog post we'll briefly go over the new state encryption feature coming out in OpenTofu 1.7. This is a work-in-progress and various implementation details of the feature could possibly change.&lt;/p&gt;

&lt;h3&gt;
  
  
  Video
&lt;/h3&gt;

&lt;p&gt;If you want to watch a video explaining all of the aspects of state encryption, check out the official video released by OpenTofu: &lt;a href="https://www.youtube.com/embed/rR4IbhlRSkI?si=IRt95ACIDA6nTeyy" rel="noopener noreferrer"&gt;https://www.youtube.com/embed/rR4IbhlRSkI?si=IRt95ACIDA6nTeyy&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why state encryption is important
&lt;/h2&gt;

&lt;p&gt;When creating resources with OpenTofu, sensitive data or secrets are stored in the state file. The state file is in clear-text and unencrypted. This opens up the opportunity for someone with access to the state file to gain elevated access to another system using the clear-text sensitive data in the state file.&lt;/p&gt;

&lt;p&gt;With data encryption, OpenTofu can be passed an encryption key to encrypt a state file or plan file. Environment variables or third-party key management systems such as AWS KMS, GCP Secrets Manager, or Azure Keyvault can be used to generate the client-side key. OpenTofu uses the key to encrypt not only the state file but also the plan file.&lt;/p&gt;

&lt;p&gt;Since this is client-side encryption, an attacker would have to have access to the state storage and the encryption key to read sensitive data from the state file.&lt;/p&gt;

&lt;p&gt;This improves an organizations security posture by following the standard layered security model.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuring encryption
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://github.com/opentofu/opentofu/blob/main/docs/state_encryption.md" rel="noopener noreferrer"&gt;State encryption&lt;/a&gt; technical documentation goes into detail on how to configure state and plan encryption in your OpenTofu code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Enable encryption
&lt;/h3&gt;

&lt;p&gt;In order to use the new encryption feature, you must include &lt;code&gt;encryption&lt;/code&gt; in the &lt;code&gt;terraform&lt;/code&gt; block:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;terraform {
  encryption {
    // Encryption options
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are a few other options you must specify to enable encryption. These include configuring your &lt;code&gt;key_provider&lt;/code&gt; and &lt;code&gt;method&lt;/code&gt;. See &lt;a href="https://github.com/opentofu/opentofu/blob/main/docs/state_encryption.md" rel="noopener noreferrer"&gt;State encryption&lt;/a&gt; for details. Official documentation to come&lt;br&gt;
when 1.7 is released.&lt;/p&gt;

&lt;h3&gt;
  
  
  Gotchas
&lt;/h3&gt;

&lt;p&gt;There are a few gotchas with this implementation that may change over time.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Encryption can only be configured globally.&lt;/li&gt;
&lt;li&gt;Pre-configured encryption settings cannot be included in modules.&lt;/li&gt;
&lt;li&gt;Encryption only protects state and plan files at-rest.&lt;/li&gt;
&lt;li&gt;Encryption does not change the output shown by the &lt;code&gt;tofu&lt;/code&gt; command (json/show/plan).&lt;/li&gt;
&lt;li&gt;Encryption only protects against unauthorized access&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Key rollover
&lt;/h2&gt;

&lt;p&gt;Key rollover is the ability to transition from one encryption key method to another.&lt;/p&gt;

&lt;p&gt;To facilitate a rollover, the &lt;code&gt;fallback&lt;/code&gt; configuration block should be used when renaming key providers or methods.&lt;/p&gt;

&lt;h2&gt;
  
  
  Environment variables
&lt;/h2&gt;

&lt;p&gt;Encryption can also be configured using environment variables for maximum flexibility. All of the configuration explained in the &lt;a href="https://github.com/opentofu/opentofu/blob/main/docs/state_encryption.md" rel="noopener noreferrer"&gt;State encryption&lt;/a&gt; can be configured using the &lt;code&gt;TF_ENCRYPTION&lt;/code&gt;&lt;br&gt;
environment variable and passed to the &lt;code&gt;tofu&lt;/code&gt; command.&lt;/p&gt;

&lt;h2&gt;
  
  
  Timeline
&lt;/h2&gt;

&lt;p&gt;State encryption is slated to be released with OpenTofu 1.7. This will potentially be followed up by a state encryption library in OpenTofu 1.8.&lt;/p&gt;

&lt;h2&gt;
  
  
  Interesting links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/opentofu/opentofu/issues/874" rel="noopener noreferrer"&gt;RFC: Client Side State Encryption&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/opentofu/opentofu/issues/1030" rel="noopener noreferrer"&gt;Implementation details&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/opentofu/opentofu/blob/main/docs/state_encryption.md" rel="noopener noreferrer"&gt;Technical description&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Terrateam
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://terrateam.io" rel="noopener noreferrer"&gt;Terrateam&lt;/a&gt; integrates seamlessly with OpenTofu. &lt;a href="https://terrateam.io/demo" rel="noopener noreferrer"&gt;Schedule a demo&lt;/a&gt; to see OpenTofu and Terrateam side by side.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
