Skip to content

Commit

Permalink
[ci] Test infrastructure deployment to AWS (#978)
Browse files Browse the repository at this point in the history
* 874: Automate creation of the infrastructure for the first ci environment

* Fix login with session token

* Add aws_iam_path variable to scope resources created

* Add support for permissions boundary

* Add AWS_SESSION_TOKEN to docker container

* Only plan

* Remove path from iam resources

* Expose node group arn as output

* Grant administrator access to kubernetes

* Add README with debugging instructions

* Trigger on PR

* Update workflow

* Update workflow

* Update workflow

* Update workflow

* Update workflow

* Update test script

* exit code from container

* Add kubernetes provider configuration

* Grant explicitely GithubCI role to K8s

* Keep only generated files output

* Add title

* Remove unnecessary version

* Clean up

* Manage operations/ci/aws-1/variables.tf with utility

* new line end of file

* Update documentation

* Improve README

* Enable deploy workflow on master push

* Remove pull_request trigger

* Remove master push trigger
  • Loading branch information
barroco authored Dec 19, 2023
1 parent 4530257 commit 462e8f8
Show file tree
Hide file tree
Showing 27 changed files with 716 additions and 71 deletions.
48 changes: 48 additions & 0 deletions .github/workflows/dss-deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
name: Deploy DSS
on:
workflow_dispatch: {}
jobs:
deploy:
name: Deploy DSS to AWS
runs-on: ubuntu-latest
if: github.repository == 'interuss/dss' || github.repository == 'Orbitalize/dss'
concurrency:
group: dss-deploy-aws
cancel-in-progress: false
permissions:
id-token: write
contents: read
steps:
- name: Job information
run: |
echo "Job information"
echo "Trigger: ${{ github.event_name }}"
echo "Host: ${{ runner.os }}"
echo "Repository: ${{ github.repository }}"
echo "Branch: ${{ github.ref }}"
docker images
- name: Checkout
uses: actions/checkout@v2
with:
fetch-depth: 0

- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::301042233698:role/InterUSSGithubCI
aws-region: us-east-1
mask-aws-account-id: true
role-duration-seconds: 1800

- name: Caller Id
run: |
aws sts get-caller-identity
- name: Test Deployment Scenario AWS-1
shell: bash
working-directory: ./deploy/operations/
env:
COMPOSE_PROFILES: aws-1
run: |
docker compose up --exit-code-from ci-aws-1
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -128,4 +128,7 @@ test/e2e_test_result
go

# vscode files
.vscode
.vscode

# terraform
.terraform*
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
resource "aws_eks_cluster" "kubernetes_cluster" {
name = var.cluster_name
role_arn = aws_iam_role.dss-cluster.arn

vpc_config {
subnet_ids = aws_subnet.dss[*].id
endpoint_public_access = true
public_access_cidrs = [
public_access_cidrs = [
"0.0.0.0/0"
]
}
Expand All @@ -26,7 +26,7 @@ resource "aws_eks_node_group" "eks_node_group" {
node_role_arn = aws_iam_role.dss-cluster-node-group.arn
disk_size = 100
node_group_name_prefix = aws_eks_cluster.kubernetes_cluster.name
instance_types = [
instance_types = [
var.aws_instance_type
]

Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,3 @@
data "tls_certificate" "cluster_oidc_provider" {
url = aws_eks_cluster.kubernetes_cluster.identity[0].oidc[0].issuer
}

resource "aws_iam_openid_connect_provider" "cluster_provider" {
client_id_list = ["sts.amazonaws.com"]
thumbprint_list = data.tls_certificate.cluster_oidc_provider.certificates[*].sha1_fingerprint
url = data.tls_certificate.cluster_oidc_provider.url
}

resource "aws_eks_addon" "aws-ebs-csi-driver" {
addon_name = "aws-ebs-csi-driver"
Expand Down
98 changes: 56 additions & 42 deletions deploy/infrastructure/dependencies/terraform-aws-kubernetes/iam.tf
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,24 @@ locals {
}

resource "aws_iam_role" "dss-cluster" {
// EKS does not support a path in the role arn
name = "${var.cluster_name}-dss-cluster"

assume_role_policy = <<POLICY
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "eks.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
POLICY
assume_role_policy = jsonencode(
{
"Version" : "2012-10-17",
"Statement" : [
{
"Effect" : "Allow",
"Principal" : {
"Service" : "eks.amazonaws.com"
},
"Action" : "sts:AssumeRole"
}
]
})

permissions_boundary = var.aws_iam_permissions_boundary
}

# Policy used by internal kubernetes services to access AWS resources.
Expand All @@ -31,30 +33,66 @@ resource "aws_iam_role_policy_attachment" "dss-cluster-service" {
role = aws_iam_role.dss-cluster.name
}

# Roles

resource "aws_iam_role" "dss-cluster-node-group" {
name = "${var.cluster_name}-cluster-node-group"

assume_role_policy = jsonencode({
Statement = [
{
Action = "sts:AssumeRole"
Effect = "Allow"
Action = "sts:AssumeRole"
Effect = "Allow"
Principal = {
Service = "ec2.amazonaws.com"
}
}
]
Version = "2012-10-17"
Version = "2012-10-17"
})

permissions_boundary = var.aws_iam_permissions_boundary
}

// EBS

resource "aws_iam_role" "AmazonEKS_EBS_CSI_DriverRole" {
name = "${var.cluster_name}-AmazonEKS_EBS_CSI_DriverRole"

assume_role_policy = jsonencode({
"Version" : "2012-10-17",
"Statement" : [
{
"Effect" : "Allow",
"Principal" : {
"Federated" : format("arn:aws:iam::${local.aws_account_id}:%s", replace(local.aws_cluster_oidc_issuer, "https://", "oidc-provider/")),
},
"Action" : "sts:AssumeRoleWithWebIdentity",
"Condition" : {
"StringEquals" : {
format("%s:aud", replace(local.aws_cluster_oidc_issuer, "https://", "")) : "sts.amazonaws.com",
format("%s:sub", replace(local.aws_cluster_oidc_issuer, "https://", "")) : "system:serviceaccount:kube-system:ebs-csi-controller-sa"
}
}
}
]
})

permissions_boundary = var.aws_iam_permissions_boundary
}

// Policies

resource "aws_iam_policy" "AWSLoadBalancerControllerPolicy" {
name = "${var.cluster_name}-AWSLoadBalancerControllerPolicy"
name = "${var.cluster_name}-AWSLoadBalancerControllerPolicy"

# Source: https://docs.aws.amazon.com/eks/latest/userguide/aws-load-balancer-controller.html
# Template: https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/v2.4.4/docs/install/iam_policy.json
policy = file("${path.module}/AWSLoadBalancerControllerPolicy.json")
}

// Attachments

resource "aws_iam_role_policy_attachment" "AWSLoadBalancerControllerPolicy" {
policy_arn = aws_iam_policy.AWSLoadBalancerControllerPolicy.arn
role = aws_iam_role.dss-cluster-node-group.name
Expand All @@ -70,35 +108,11 @@ resource "aws_iam_role_policy_attachment" "AmazonEKS_CNI_Policy" {
role = aws_iam_role.dss-cluster-node-group.name
}

## Docker registry
resource "aws_iam_role_policy_attachment" "AmazonEC2ContainerRegistryReadOnly" {
policy_arn = "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly"
role = aws_iam_role.dss-cluster-node-group.name
}

## EBS
resource "aws_iam_role" "AmazonEKS_EBS_CSI_DriverRole" {
name = "${var.cluster_name}-AmazonEKS_EBS_CSI_DriverRole"

assume_role_policy = jsonencode({
"Version" : "2012-10-17",
"Statement" : [
{
"Effect" : "Allow",
"Principal" : {
"Federated" : format("arn:aws:iam::${local.aws_account_id}:%s", replace(local.aws_cluster_oidc_issuer, "https://", "oidc-provider/")),
},
"Action" : "sts:AssumeRoleWithWebIdentity",
"Condition" : {
"StringEquals" : {
format("%s:aud", replace(local.aws_cluster_oidc_issuer, "https://", "")) : "sts.amazonaws.com",
format("%s:sub", replace(local.aws_cluster_oidc_issuer, "https://", "")) : "system:serviceaccount:kube-system:ebs-csi-controller-sa"
}
}
}
]
})
}

resource "aws_iam_role_policy_attachment" "AmazonEKS_EBS_CSI_DriverRole" {
policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonEBSCSIDriverPolicy"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ terraform {
tls = {
source = "hashicorp/tls"
}
helm = {
source = "hashicorp/helm"
}
}
}

Expand All @@ -20,14 +23,14 @@ provider "aws" {
}
}

data "aws_eks_cluster_auth" "kubernetes_cluster" {
name = aws_eks_cluster.kubernetes_cluster.name
}

provider "helm" {
kubernetes {
host = aws_eks_cluster.kubernetes_cluster.endpoint
cluster_ca_certificate = base64decode(aws_eks_cluster.kubernetes_cluster.certificate_authority[0].data)
exec {
api_version = "client.authentication.k8s.io/v1beta1"
args = ["eks", "get-token", "--cluster-name", var.cluster_name]
command = "aws"
}
token = data.aws_eks_cluster_auth.kubernetes_cluster.token
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
data "tls_certificate" "cluster_oidc_provider" {
url = aws_eks_cluster.kubernetes_cluster.identity[0].oidc[0].issuer
}

resource "aws_iam_openid_connect_provider" "cluster_provider" {
client_id_list = ["sts.amazonaws.com"]
thumbprint_list = data.tls_certificate.cluster_oidc_provider.certificates[*].sha1_fingerprint
url = data.tls_certificate.cluster_oidc_provider.url
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,8 @@ output "gateway_address" {

output "workload_subnet" {
value = data.aws_subnet.main_subnet.id
}

output "iam_role_node_group_arn" {
value = aws_iam_role.dss-cluster-node-group.arn
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,16 @@ variable "aws_route53_zone_id" {
EOT
}

variable "aws_iam_permissions_boundary" {
type = string
description = <<-EOT
AWS IAM Policy ARN to be used for permissions boundaries on created roles.
Example: `arn:aws:iam::123456789012:policy/GithubCIPermissionBoundaries`
EOT
}


variable "app_hostname" {
type = string
description = <<-EOT
Expand Down
9 changes: 9 additions & 0 deletions deploy/infrastructure/modules/terraform-aws-dss/TFVARS.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,15 @@ Leave empty to disable record creation.
Example: `Z0123456789ABCDEFGHIJ`


### aws_iam_permissions_boundary

*Type: `string`*

AWS IAM Policy ARN to be used for permissions boundaries on created roles.

Example: `arn:aws:iam::123456789012:policy/GithubCIPermissionBoundaries`


### app_hostname

*Type: `string`*
Expand Down
16 changes: 9 additions & 7 deletions deploy/infrastructure/modules/terraform-aws-dss/main.tf
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
module "terraform-aws-kubernetes" {
# See variables.tf for variables description.
cluster_name = var.cluster_name
aws_region = var.aws_region
app_hostname = var.app_hostname
crdb_hostname_suffix = var.crdb_hostname_suffix
aws_instance_type = var.aws_instance_type
aws_route53_zone_id = var.aws_route53_zone_id
node_count = var.node_count
cluster_name = var.cluster_name
aws_region = var.aws_region
app_hostname = var.app_hostname
crdb_hostname_suffix = var.crdb_hostname_suffix
aws_instance_type = var.aws_instance_type
aws_route53_zone_id = var.aws_route53_zone_id
aws_iam_path = var.aws_iam_path
aws_iam_permissions_boundary = var.aws_iam_permissions_boundary
node_count = var.node_count

source = "../../dependencies/terraform-aws-kubernetes"
}
Expand Down
10 changes: 10 additions & 0 deletions deploy/infrastructure/modules/terraform-aws-dss/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,16 @@ variable "aws_route53_zone_id" {
EOT
}

variable "aws_iam_permissions_boundary" {
type = string
description = <<-EOT
AWS IAM Policy ARN to be used for permissions boundaries on created roles.
Example: `arn:aws:iam::123456789012:policy/GithubCIPermissionBoundaries`
EOT
}


variable "app_hostname" {
type = string
description = <<-EOT
Expand Down
2 changes: 1 addition & 1 deletion deploy/infrastructure/utils/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ This directory contains the following tools to simplify the management of the te

1. `generate_terraform_variables.sh`: Terraform variables can't be shared between modules without repeating their definition at every level of encapsulation.
To prevent repeating ourselves and to maintain a consistent level of quality for every module and dependencies, this script takes variables
in the `definitions` directory and creates a `variables.tf` file in each modules with the appropriate content.
in the `definitions` directory and creates a `variables.tf` file in each modules with the appropriate content.
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
variable "aws_iam_permissions_boundary" {
type = string
description = <<-EOT
AWS IAM Policy ARN to be used for permissions boundaries on created roles.
Example: `arn:aws:iam::123456789012:policy/GithubCIPermissionBoundaries`
EOT
}
Loading

0 comments on commit 462e8f8

Please sign in to comment.