AWS

Self-hosting on AWS

This guide provides AWS-specific information for deploying Membrane in your AWS environment.

S3 Storage configuration

Create the necessary S3 buckets:

resource "aws_s3_bucket" "tmp" {
  bucket = "${var.environment}-integration-app-tmp"
}

resource "aws_s3_bucket" "connectors" {
  bucket = "${var.environment}-integration-app-connectors"
}

resource "aws_s3_bucket" "static" {
  bucket = "${var.environment}-integration-app-static"
}

# Lifecycle rules for tmp bucket
resource "aws_s3_bucket_lifecycle_configuration" "tmp" {
  bucket = aws_s3_bucket.tmp.id

  rule {
    id     = "cleanup"
    status = "Enabled"

    filter {
      prefix = ""
    }

    expiration {
      days = 7
    }
  }
}

# CORS configuration for static bucket
resource "aws_s3_bucket_cors_configuration" "static" {
  bucket = aws_s3_bucket.static.id

  cors_rule {
    allowed_headers = ["*"]
    allowed_methods = ["GET"]
    allowed_origins = ["*"]
    max_age_seconds = 3000
  }
}

Create CloudFront Distribution:

resource "aws_cloudfront_origin_access_control" "static" {
  name                              = "${var.environment}-static-oac"
  description                       = "OAC for static S3 bucket"
  origin_access_control_origin_type = "s3"
  signing_behavior                  = "always"
  signing_protocol                  = "sigv4"
}

resource "aws_cloudfront_distribution" "static" {
  enabled             = true
  default_root_object = "index.html"

  aliases = ["static.${var.environment}.${var.hosted_zone_name}"]

  origin {
    domain_name              = aws_s3_bucket.static.bucket_regional_domain_name
    origin_id                = aws_s3_bucket.static.id
    origin_access_control_id = aws_cloudfront_origin_access_control.static.id
  }

  default_cache_behavior {
    allowed_methods        = ["GET", "HEAD"]
    cached_methods         = ["GET", "HEAD"]
    target_origin_id       = aws_s3_bucket.static.id
    viewer_protocol_policy = "redirect-to-https"
    forwarded_values {
      query_string = false
      cookies {
        forward = "none"
      }
    }
  }

  price_class = "PriceClass_100"
  restrictions {
    geo_restriction {
      restriction_type = "none"
    }
  }

  viewer_certificate {
    acm_certificate_arn      = aws_acm_certificate.cloudfront.arn
    ssl_support_method       = "sni-only"
    minimum_protocol_version = "TLSv1.2_2021"
  }

  tags = {
    Service = "core"
  }
}

resource "aws_s3_bucket_policy" "static_cloudfront" {
  bucket = aws_s3_bucket.static.id
  policy = jsonencode({
    Version = "2012-10-17",
    Statement = [
      {
        Effect = "Allow",
        Principal = {
          Service = "cloudfront.amazonaws.com"
        },
        Action   = "s3:GetObject",
        Resource = "${aws_s3_bucket.static.arn}/*",
        Condition = {
          StringEquals = {
            "AWS:SourceArn" = aws_cloudfront_distribution.static.arn
          }
        }
      }
    ]
  })
}

IAM Role Configuration

Membrane containers support AWS IAM role-based access to S3 and other AWS services. This is the preferred method over providing explicit access and secret keys.

Container IAM Configuration

To use IAM roles instead of access keys:

  1. Create an IAM role with appropriate S3 permissions
  2. Assign this role to your ECS tasks, EKS pods, or EC2 instances
  3. Omit the AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY environment variables

When running in a properly configured AWS environment, the containers will automatically use the IAM role credentials.

MongoDB on AWS

While AWS DocumentDB is technically compatible with our application, we recommend using native MongoDB (either self-hosted on EC2 or a managed MongoDB Atlas cluster) for better compatibility.

Some customers have encountered edge cases with DocumentDB due to differences in MongoDB API implementation. If you choose to use DocumentDB, be prepared for potential compatibility issues.

Redis on AWS

For Redis, you can use Amazon ElastiCache. Keep in mind that Redis is only used as a cache in our application and can be safely restarted or cleared. There's no persistent data stored in Redis that isn't recoverable from other sources.