Self-Service AWS Infrastructure for Your Devs
Tags: aws, devops, terraform, architecture
Published: 2023-03-29 18:04:08

## Intro

If you're a developer or "developer adjacent," you've probably heard about "self-service" infrastructure. As the infrastructure required to launch simple apps becomes more and more distributed and specialized, deploying these apps becomes more difficult for the ones that program them. Previously, you could just upload the new code to your html directory, and BAM! The new site is up! Now, these apps usually require multiple pieces of infrastructure to be set up to be delivered. This allows companies to deploy only the necessary infrastructure and only pay for it when needed. Unfortunately, this adds more overhead for the developer. To combat this, DevOps teams and their subset, "Platform Engineering", are working on abstracting this process from the developers to allow them to create this infrastructure themselves on the fly when needed, without the headaches. In this article, we'll cover different strategies to build a self-service platform that deploys a simple peered VPC in AWS without the developer making any complicated decisions. So let's kick this off! 

## The Terraform Code

As I mentioned before, this is not a series that will cover a sophisticated AWS SaaS deployment. We will keep the AWS code very simple and focus more on the pipeline and the self-service aspects than the deployed infrastructure. So we're going to stick to a simple VPC:

### Main VPC Code

```
# ./shared_infra/main.tf
provider "aws" {
  region = var.region
}

resource "aws_vpc" "main" {
  cidr_block       = "10.0.0.0/16"
  tags = {
    Name = "main"
  }
}
```
```
# ./shared_infra/variables.tf
# Set the appropriate default region here.
variable "region" {
    type = "string"
    default = "us-east-1"
}
```
```
# ./shared_infra/versions.tf
# specify different versions if appropriate. 

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 4.15.0"
    }

    random = {
      source  = "hashicorp/random"
      version = "3.1.0"
    }
  }
}
```
### Client VPC Code

```
# ./client_infra/main.tf
provider "aws" {
  region = var.region
}

data "aws_vpc" "main" {
  filter {
    name   = "tag:Name"
    values = ["main"]
  }
}

resource "aws_vpc" "client_vpc" {
  cidr_block = var.vpc_cidr

  tags = {
    Name = "client_vpc"
  }
}

resource "aws_vpc_peering_connection" "this" {
  peer_vpc_id = aws_vpc.client_vpc.id
  vpc_id      = data.aws_vpc.main.id

  auto_accept = true

  tags = {
    Name = "VPC Peering"
  }
}

resource "aws_route" "requester" {
  route_table_id         = data.aws_vpc.main.main_route_table_id
  destination_cidr_block = aws_vpc.client_vpc.cidr_block
  vpc_peering_connection_id = aws_vpc_peering_connection.this.id
}

resource "aws_route" "accepter" {
  route_table_id         = aws_vpc.client_vpc.main_route_table_id
  destination_cidr_block = data.aws_vpc.main.cidr_block
  vpc_peering_connection_id = aws_vpc_peering_connection.this.id
}
```
```
# ./client_vpc/variables.tf
variable "region" {
    type = string
    default = "us-east-1"
}

variable "vpc_cidr" {
    type = string
    default = "10.1.0.0/16"
}

variable "client_name" {
    type = string
    default = "cool-client"
}
```
```
# ./client_infra/versions.tf
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 4.15.0"
    }

    random = {
      source  = "hashicorp/random"
      version = "3.1.0"
    }
  }
}
```

## Deployment

This code is simple enough. And to deploy it, all you have to do is give the client VPC a unique name and `terraform apply` each piece individually. Easy peasy, right? Of course it is, for the one who wrote it! If you have many developers, expecting this to be deployed correctly when they add clients is, unfortunately, most likely a pipe dream. How can we deploy this in a way that allows developers to deploy easily and securely? I'll cover the overall approaches we'll take here, then we'll deep dive into them as we continue the series.

### The Managed Deployment Way

This will be the method with a lot of flexibility and a much simpler deployment process. Using [Spacelift](https://spacelift.io) and its [Blueprints ](https://spacelift.io/blog/introducing-spacelift-blueprints) feature, we'll be able to deploy a frontend for developers to use and a deployment pipeline that can deploy Terraform, Cloudformation, Pulumi, and more. We'll focus on Terraform here and build everything out, including the Spacelift resources using Terraform. This method will be incredibly flexible, but of course, it is not a free solution. To use the Blueprints feature, an enterprise account will be required. I'll show how to deploy everything before the Blueprints for those without an enterprise account, then add the Blueprints customization by the end. 


![Diagram illustrating Peered VPCs in AWS and necessary Spacelift infrastructure to create self-service](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cc90fxoqz53r600woqcm.png)

Check out the next post in this series to see the managed way.

### The AWS Code* Services + Terraform way

#### Coming soon!


### The Serverless + Cloudformation Way

#### Coming Soon!