How to make AWS SCPs By Terraform

Sarthak TyagiSarthak Tyagi
4 min read

Prerequirsite:-

  • IAM user with Administrator Permission

  • AWS cli and Do AWS configure{Enter access key and secrets key here (iam user)}

  • Install Terraform

How to install terraform in Linux

sudo apt-get update && sudo apt-get install -y gnupg software-properties-common
wget -O- https://apt.releases.hashicorp.com/gpg | \
gpg --dearmor | \
sudo tee /usr/share/keyrings/hashicorp-archive-keyring.gpg > /dev/null
gpg --no-default-keyring \
--keyring /usr/share/keyrings/hashicorp-archive-keyring.gpg \
--fingerprint
echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] \
https://apt.releases.hashicorp.com $(lsb_release -cs) main" | \
sudo tee /etc/apt/sources.list.d/hashicorp.list
sudo apt update
sudo apt-get install terraform

For SCPs You have to make some files

  1. main.tf

  2. output.tf

  3. terraform.tfvars

  4. variable.tf

  5. policies/scp_policies.json

provider "aws" {
  region = var.aws_region
}

resource "aws_organizations_policy" "custom_scp_policy" {
  name        = "CustomSCP"
  description = "A custom SCP policy"
  content     = file("${path.module}/policies/scp_policy.json")
  type        = "SERVICE_CONTROL_POLICY"
}

resource "aws_organizations_policy_attachment" "custom_scp_policy_attachment" {
  policy_id = aws_organizations_policy.custom_scp_policy.id
  target_id = var.target_id
}

Creates an AWS Organizations policy.

  • The policy is named "CustomSCP" and has a description.

  • The policy content is loaded from a file (scp_policy.json) located in the policies directory within the module path.

  • The type of policy is SERVICE_CONTROL_POLICY.

    Attaches the previously created policy to a target.

  • The policy_id is referenced from the aws_organizations_policy resource.

  • The target_id is provided by the target_id variable and determines where the policy is applied (e.g., an AWS account or organizational unit).

output.tf

output "scp_policy_id" {
  description = "The ID of the created SCP policy"
  value       = aws_organizations_policy.custom_scp_policy.id
}

Output Declaration:

  • Outputs the ID of the created Service Control Policy (SCP) so it can be used elsewhere.

  • The description provides context about what the output represents.

  • The value references the id of the aws_organizations_policy resource.

terraform.tfvars

aws_region = "eu-west-1"
target_id  = "590183704217"  # Replace with your AWS account ID or organizational unit ID

Variable Values:

  • Sets the values for the variables defined in variable.tf.

  • aws_region specifies the AWS region (e.g., eu-west-1).

  • target_id is the AWS account ID or organizational unit ID to which the SCP policy will be attached.

variable.tf

variable "aws_region" {
  description = "The AWS region to deploy in"
  default     = "eu-west-1"
}

variable "target_id" {
  description = "The ID of the AWS account or organizational unit to attach the SCP to"
  type        = string
}

Variable Declaration:

  • aws_region:

    • Description: Specifies the AWS region for deployment.

    • Default Value: eu-west-1, which can be overridden by terraform.tfvars.

  • target_id:

    • Description: Specifies the ID of the target (AWS account or organizational unit) for the SCP policy attachment.

    • Type: string, as it will hold a string representing the ID.

  • Summary

    main.tf: Contains the primary Terraform configuration for creating and attaching an AWS Organizations policy.

  • output.tf: Defines outputs to expose information about the created policy.

  • terraform.tfvars: Provides specific values for variables used in the configuration.

  • variable.tf: Declares the variables used in the configuration, including descriptions and default values.

Make a folder policies/scp_policy.json

{
    "Version": "2012-10-17",
    "Statement": [
      {
        "Effect": "Deny",
        "Action": "ec2:RunInstances",
        "Resource": "arn:aws:ec2:*:*:instance/*",
        "Condition": {
          "StringNotEquals": {
            "ec2:MetadataHttpTokens": "required"
          }
        }
      },
      {
        "Effect": "Deny",
        "Action": "ec2:RunInstances",
        "Resource": "arn:aws:ec2:*:*:instance/*",
        "Condition": {
          "NumericGreaterThan": {
            "ec2:MetadataHttpPutResponseHopLimit": "3"
          }
        }
      },
      {
        "Effect": "Deny",
        "Action": "*",
        "Resource": "*",
        "Condition": {
          "NumericLessThan": {
            "ec2:RoleDelivery": "2.0"
          }
        }
      },
      {
        "Effect": "Deny",
        "Action": "ec2:ModifyInstanceMetadataOptions",
        "Resource": "*"
      }
    ]
  }

Adding a New Policy

If you want to add another policy to your setup, you need to:

  1. Create a new policy JSON file in the policies folder, e.g., scp_policy_2.json.

  2. Update main.tf:

    • Add a new aws_organizations_policy resource that references the new policy file.

    • Add a new aws_organizations_policy_attachment resource for the new policy.

Example for a New Policy

Assume you create scp_policy_2.json with similar or different content. Update main.tf as follows:

hclCopy code# Define the new policy
resource "aws_organizations_policy" "custom_scp_policy_2" {
  name        = "CustomSCP2"
  description = "The second custom SCP policy"
  content     = file("${path.module}/policies/scp_policy_2.json")
  type        = "SERVICE_CONTROL_POLICY"
}

# Attach the new policy
resource "aws_organizations_policy_attachment" "custom_scp_policy_attachment_2" {
  policy_id = aws_organizations_policy.custom_scp_policy_2.id
  target_id = var.target_id
}

Summary

  1. Define the new policy in a new JSON file within the policies folder.

  2. Add the new policy and its attachment to main.tf.

  3. Optionally, add an output in output.tf for the new policy ID if you need to reference it later.

0
Subscribe to my newsletter

Read articles from Sarthak Tyagi directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Sarthak Tyagi
Sarthak Tyagi