This document contains configuration and deployment details for deploying the Superblocks agent to AWS.
To install Terraform on MacOS
brew tap hashicorp/tap
brew install hashicorp/tap/terraform
Terraform officially supports MacOS|Windows|Linux|FreeBSD|OpenBSD|Solaris
Check out this https://developer.hashicorp.com/terraform/downloads for more details
To get started, you'll need a superblocks_agent_key
. To generate an agent key, go to the Superblocks On-Premise Agent Setup Wizard
module "terraform_aws_superblocks" {
source = "superblocksteam/superblocks/aws"
version = "~>1.0"
vpc_id = "[VPC_ID]"
lb_subnet_ids = "[LIST_OF_SUBNET_IDS_FOR_LOAD_BALANCER]"
ecs_subnet_ids = "[LIST_OF_SUBNET_IDS_FOR_SUPERBLOCKS_AGENT_ECS_CLUSTER]"
domain = "[DOMAIN]"
subdomain = "[SUBDOMAIN_FOR_SUPERBLOCKS_AGENT]"
superblocks_agent_key = "[SUPERBLOCKS_AGENT_KEY]"
}
If you are in the EU region, ensure that
superblocks_agent_data_domain = "eu.superblocks.com"
is set in your configuration in the module block.
To find your VPC use aws ec2 describe-vpcs
or by finding them in the AWS management console.
terraform init
terraform apply
ECS instances running the Superblocks On-Premise Agent are configured to receive traffic from a private Elastic Load Balancer. Allow public traffic to your On-Premise Agent by adding
lb_internal = false
The module by default deploys the OPA within an existing VPC. If you want your agent to access data across multiple VPCs, you can update the module to create a new VPC then set up VPC peering between the newly configured VPC and existing AWS VPCs. To update the module to create a new VPC
create_vpc = true
For more details on configuring VPC peering see Connect VPCs using VPC peering.
A default security group will be created with an ingress cidr blocks 0.0.0.0/0
. To use your own security group
create_sg = false
security_group_ids = "<LIST_OF_YOUR_SECURITY_GROUP_IDS>"
A new Elastic Load Balancer will be created by default to handle TLS termination before sending traffic to your ECS instances. To use an existing Loading Balancer, update the module to include
create_lb = false
lb_target_group_arns = "[<YOUR_TARGET_GROUP_ARNS>]"
To find your target ground ARN use aws elbv2 describe-target-groups
or by finding the Load Balancer in the AWS management console.
If you use Route53 for domain management you can use the Terraform module to generate a DNS record and certificate for your agent, and associated both with your Load Balancer. If you don't use Route53 or want to use an existing certificate & DNS record, add the following to your configuration
create_certs = false
create_dns = false
certificate_arn = "<YOUR_CERTIFICATE_ARN>"
To find the certificate's ARN use aws acm list-certificates
or by finding the Certificate in the AWS management console. For additional instructions on creating a certificate manually see Issue and manage certificates.
Configure the CPU & memory limits allocated to your ECS instances use
container_cpu = 1024
container_memory = 4096
AWS will automatically scale your ECS instances based on traffic. To configure the minimum and maximum number of instances the agent can scale to, set
container_min_capacity = 1
container_max_capacity = 10
By default, security groups will be created for both the loadbalancer and ECS cluster. You can modify the default security ECS group rules with the following variables:
variable "allowed_load_balancer_sg_ids" {
type = list(string)
default = []
description = "Specify loadbalancer security group ids to allow traffic from. Only used when create_ecs_sg is set to true."
}
variable "ecs_sg_egress_with_cidr_blocks" {
type = list(map(string))
default = [
{
from_port = 0
to_port = 0
protocol = "-1"
description = "All egress traffic"
cidr_blocks = "0.0.0.0/0"
}
]
description = "Specify egress rules for the ECS cluster. Only used if create_ecs_sg is set to true."
}
You can modify the default loadbalancer security group rules with the following variables:
variable "lb_sg_ingress_with_cidr_blocks" {
type = list(map(string))
default = [
{
from_port = 443
to_port = 443
protocol = "tcp"
description = "HTTPS"
cidr_blocks = "0.0.0.0/0"
},
{
from_port = 8443
to_port = 8443
protocol = "tcp"
description = "GRPCS"
cidr_blocks = "0.0.0.0/0"
}
]
description = "Specify ingress rules for the load balancer. Only used if create_lb_sg is set to true."
}
variable "lb_sg_egress_with_cidr_blocks" {
type = list(map(string))
default = [
{
from_port = 0
to_port = 0
protocol = "-1"
description = "All Egress"
cidr_blocks = "0.0.0.0/0"
}
]
description = "Specify egress rules for the load balancer. Only used if create_lb_sg is set to true."
}
To disable default security groups, you can set
create_lb_sg = false
create_ecs_sg = false
You may specify your own security groups to be assigned to the loadbalancer and the ECS cluster using the following variables:
variable "lb_security_group_ids" {
type = list(string)
default = []
description = "Specify additional security groups to associate with the load balancer. This will be joined with the default security group if created."
}
variable "ecs_security_group_ids" {
type = list(string)
default = []
description = "Specify additional security groups to associate with the ECS cluster. This will be joined with the default security group if created."
}
The ECS Task Execution Role enables the ECS container and Fargate agents permmissions to do core actions on AWS necessary for the functioning of the container. This is different than the ECS Task Role which is described below and is to give your application permission to access AWS APIs.
By default you don't have to do anything and the ECS Task Execution IAM Role is created and setup to minimally enable your ECS container to send logs to CloudWatch.
If you need to enable the ECS task to have additional IAM permisions to do things like pull containers from AWS ECR private repository, you will need to add an additional policy to the automatically created Task Execution Role.
This can be accomplished in two ways.
variable "additional_ecs_execution_task_policy_arns" {
type = list(string)
default = []
description = "List of ARNs of Additional iam policy to attach to the ECS execution role"
}
You can do this by passing in a list of ARNs for policies you create in your Terraform module as shown in this example:
data "aws_iam_policy_document" "execution_ecr_policy" {
statement {
sid = "allowECR"
effect = "Allow"
actions = [
"ecr:BatchGetImage",
"ecr:GetDownloadUrlForLayer",
"ecr:GetAuthorizationToken"
]
resources = ["*"]
}
}
resource "aws_iam_policy" "ecr_policy" {
name = "superblocks-agent-ecr-policy"
description = "IAM Policy to allow access to ECR"
policy = data.aws_iam_policy_document.execution_ecr_policy.json
}
module "terraform_aws_superblocks" {
source = "superblocksteam/superblocks/aws"
version = "~>1.0"
additional_ecs_execution_task_policy_arns = [aws_iam_policy.ecr_policy]
# ... The rest of your config ...
}
The other option is to get the Task Execution Role name (module.superblocks_agent.ecs_execution_agent_role.name
) from the output of terraform-aws-superblocks
and attach your policies to the role.
An example of doing this in your Terraform module using the policy creation shown in the previous example. Instead of using additional_ecs_execution_task_policy_arns = [aws_iam_policy.ecr_policy]
you could attach the policy directly to the Task Execution Role yourself:
resource "aws_iam_role_policy_attachment" "ecr_policy_attachment" {
role = module.superblocks_agent.ecs_execution_agent_role.name
policy_arn = aws_iam_policy.ecr_policy.arn
depends_on = [
module.superblocks_agent
]
}
The Task IAM Role is different and in addition to the Task Execution Role. The Task IAM Role
is optional, but you will need it if you want to leverage instance credentials you get automatically from the Container Credential Provider to access other AWS APIs via an SDK.
NOTE: As of this writing (10/14/2023) instance credentials for Python boto3 doesn't actually work in Superblocks. But a ticket is in process to fix this
To use this, you must:
- Create the Role (its different than the Task Execution Role)
- Create the policy to give the kind of access you want
- Attach the policy to the role
- Pass in the ARN of the role to the SuperBlocks terraform module
The definition for the parameter to pass in the role ARN is:
variable "superblocks_agent_role_arn" {
type = string
default = null
description = "ARN of the Task IAM role (not the Task Execution) that allows the Superblocks Agent container(s) to make calls to other AWS services. This can be leveraged for using Superblocks integrations like S3, DynamoDB, etc."
}
An example of doing this to give access to an S3 bucket:
# List of buckets we want to control access to
locals {
s3_buckets_list = [
"my-bucket-000",
"my-bucket-001",
"my-bucket-002"
]
}
# Policy to allow read acccess to some S3 buckets
data "aws_iam_policy_document" "s3_read_access" {
statement {
sid = "allowListAllMyBucketsS3"
effect = "Allow"
actions = [
"s3:ListAllMyBuckets"
]
resources = ["*"]
}
statement {
sid = "allowListS3"
effect = "Allow"
actions = [
"s3:ListBucket"
]
resources = formatlist("arn:aws:s3:::%s", local.s3_buckets_list)
}
statement {
sid = "allowReadS3"
effect = "Allow"
actions = [
"s3:GetObject"
]
resources = distinct(
compact(
concat(
formatlist("arn:aws:s3:::%s", local.s3_buckets_list),
formatlist("arn:aws:s3:::%s/*", local.s3_buckets_list)
)
)
)
}
}
# Create an actual policy from the previous definition
resource "aws_iam_policy" "s3_policy" {
name = "superblocks-agent-s3-access-policy"
description = "IAM Policy to allow readonly access to s3 buckets"
policy = data.aws_iam_policy_document.s3_read_access.json
}
# Define the assume_role policy for the Task Role
data "aws_iam_policy_document" "assume_role" {
statement {
sid = "AllowECSService"
actions = [
"sts:AssumeRole"
]
effect = "Allow"
principals {
type = "Service"
identifiers = [
"ecs-tasks.amazonaws.com"
]
}
}
}
# Create the Task Role and attach the assume role and the s3 policy
resource "aws_iam_role" "superblocks_agent_task" {
name = "superblocks-agent-task"
assume_role_policy = data.aws_iam_policy_document.assume_role.json
managed_policy_arns = [
aws_iam_policy.s3_policy.arn
]
}
module "terraform_aws_superblocks" {
source = "superblocksteam/superblocks/aws"
version = "~>1.0"
superblocks_agent_role_arn = aws_iam_role.superblocks_agent_task.arn
# ... The rest of your config ...
}
The Superblocks agent can be extended in various ways. When extending the base image, you'll need to host your own private image. If your custom image is hosted in a private container repository, you can set the following variables so the Terraform module has permission to download your container.
superblocks_agent_image = "myprivaterepository.io/my-image:my-tag"
superblocks_repository_credentials_secret_arn = "arn:aws:secretsmanager:region:my_aws_account_id:my_secret:my_secret_name"
variable "superblocks_agent_tags" {
type = string
default = "profile:*"
description = <<EOF
Use this variable to specify which profile-specific workloads can be executed on this agent.
It accepts a comma (and colon) separated string representing key-value pairs, and currently only the "profile" key is used.
Some examples:
- To support all API executions: "profile:*"
- To support staging and production: "profile:staging,profile:production"
- To support only staging: "profile:staging"
- To support only production: "profile:production"
- To support a custom profile: "profile:custom_profile_key"
EOF
}
variable "superblocks_agent_image" {
type = string
default = "ghcr.io/superblocksteam/agent"
description = "The docker image used by Superblocks Agent container instance"
}
variable "name_prefix" {
type = string
default = "superblocks"
description = "This will be prepended to the name of each AWS resource created by this module"
}
variable "tags" {
type = map(string)
default = {}
description = "A series of tags that will be added to each AWS resource created by this module"
}
variable "superblocks_grpc_msg_res_max" {
type = string
default = "100000000"
description = "The maximum message size in bytes allowed to be sent by the gRPC server. This is used to prevent malicious clients from sending large messages to cause memory exhaustion."
}
variable "superblocks_grpc_msg_req_max" {
type = string
default = "30000000"
description = "The maximum message size in bytes allowed to be received by the gRPC server. This is used to prevent malicious clients from sending large messages to cause memory exhaustion."
}
variable "superblocks_timeout" {
type = string
default = "10000000000"
description = "The maximum amount of time in nanoseconds before a request is aborted. This applies for http requests against the Superblocks server and does not apply to the execution time limit of a workload."
}
variable "superblocks_log_level" {
type = string
default = "info"
description = "Logging level for the superblocks agent. Accepted values are 'debug', 'info', 'warn', 'error', 'fatal', 'panic'."
}
variable "superblocks_agent_handle_cors" {
type = bool
default = true
description = "Whether to enable CORS support for the Superblocks Agent. This is required if you don't have a reverse proxy in front of the agent that handles CORS. This will allow CORS for all origins."
}
variable "superblocks_agent_environment_variables" {
type = list(map(string))
default = []
description = "Environment variables that will be passed to the Superblocks Agent container(s). This can be specified in the form of [{name = "key", value = "value"}]."
}
deploy_in_ecs
variable has been completely removed.create_sg
variable replaced by two new variables:create_lb_sg
creates a default loadbalancer security group.create_ecs_sg
creates a default loadbalancer security group.
security_group_ids
variable replaced by two new variables:lb_security_group_ids
allows users to set security groups for the loadbalancer, ifcreate_lb
is set to true.ecs_security_group_ids
allows users to set security groups for the ECS cluster.
create_dns
no longer creates both certificate and the DNS entry. A newcreate_certs
flag exists to create create the ACM certificate.create_dns
now only determines whether the DNS entry to point to the loadbalancer is created.