Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

build: Add infrastructure to setup an account for the first time #104

Merged
merged 12 commits into from
Sep 26, 2024
Merged
6 changes: 2 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,11 +98,9 @@ To run this app locally, follow these steps:

It's in `./deployment/cloud` and we're using [OpenTofu](https://opentofu.org/)

### Credentials
### Overview of AWS account setup, including information on getting credentials

For now, contact Niki for least-privileged IAM user credentials. These will be used to assume the necessary roles. ([TODO as part of this issue](https://github.com/uw-ssec/post-disaster-comms/issues/61): find a better way to distribute these)

This user will assume the necessary roles to get things going
Please see our information [here](./deployment/cloud/aws/README.md)

### Editing deployment/values.cloud.yaml

Expand Down
86 changes: 86 additions & 0 deletions deployment/cloud/aws/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# AWS Infrastructure Information

## Info

Infrastructure has been split into two separate stacks, with different considerations and ownership for each

### `account` - Account-level configurations accessible by account owners and admistrators

Everything in here is the foundation needed for everything else to work.

This is intended to be run extremely rarely by a user with elevated permissions.

It configures the S3 bucket that stores the terraform state, as well as the `deploy` IAM role that is assumed to deploy everything in `infrastructure`

New resources should only be added here if they would be needed to set up a brand new account.

### `infrastructure` - AWS resources and configuration to run the Support Sphere project

This is where all the "real" resources needed to run the Support Sphere cloud server configurations -- server setup, IAM roles to run operational scripts,

Every resource created here will be named starting with the "resource prefix", a combination of the project name (`supportsphere`) and the neighborhood for which this infrastructure is created. An example resource prefix is `supportsphere-laurelhurst`.

Every resource here will also be tagged with the project name and neighborhood.

This is probably where you want to add new resources.

## Create and update account-level infrastructure

#### Initialize the account-setup infrastructure on your machine

From the `tofu init` docs

> This is the first command that should be run for any new or existing
OpenTofu configuration per machine. This sets up all the local data
necessary to run OpenTofu that is typically not committed to version
control.

```
pixi run cloud-account-init
```

### View differences between live and local changes

```
pixi run cloud-account-plan
```

### Deploy configurations

```
pixi run cloud-account-deploy
```

## AWS user administration

### Create users that can interact with ops scripts and deploy resources in `infrastructure`

```
pixi run cloud-account-user-controls add -u <name>
```

This command creates a new IAM User `<name>-assumer`, attaches them to the `ssec-eng` user group, creates access keys for the user to access the CLI, and prints out commands for someone to configure their AWS CLI with credentials for the new user.

This should be run by an account owner or admin on behalf of an engineer who will work to deploy & maintain this infrastructure.

The account owner/admin will run this command, and send the output to the engineer.

### Revoke access to a user

```
pixi run cloud-account-user-controls delete -u <name>
```

### Rotate a user's access keys

Useful if existing keys have leaked but you don't want to outright delete the associate IAM user

```
pixi run cloud-account-user-controls rotate -u <name>
```

### List all existing access users in the `ssec-eng` group and their associated access keys

```
pixi run cloud-account-user-controls list
```
20 changes: 20 additions & 0 deletions deployment/cloud/aws/account/.terraform.lock.hcl

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

177 changes: 177 additions & 0 deletions deployment/cloud/aws/account/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.61"
}
}

backend "s3" {
bucket = "${var.account_resource_prefix}-${var.account_id}-opentofu-state"
key = "account/terraform.tfstate"
region = "us-west-2"
}
}

provider "aws" {
region = "us-west-2"

// Tags all resources created from this provider with {"Project": <project name input>, "Neighborhood": <neighborhood input>}
// as well as any additional tags provided
default_tags {
tags = merge(
var.account_additional_tags
)
}
}

# s3 tf state bucket

resource "aws_s3_bucket" "tf_state" {
bucket = "${var.account_resource_prefix}-${var.account_id}-opentofu-state"
}

resource "aws_s3_bucket_versioning" "this" {
bucket = aws_s3_bucket.tf_state.bucket

versioning_configuration {
status = "Enabled"
}

}

resource "aws_s3_bucket_public_access_block" "example" {
bucket = aws_s3_bucket.tf_state.bucket

block_public_acls = true
block_public_policy = true
ignore_public_acls = true
restrict_public_buckets = true
}

# deploy role
resource "aws_iam_role" "deploy" {
name = "${var.account_resource_prefix}-deploy"
description = "Role used to deploy infrastructure for the Support Sphere app, part of the Post-Disaster communications project."
assume_role_policy = jsonencode({
Version = "2012-10-17",
Statement = [
{
Effect = "Allow",
Principal = {
AWS = "arn:aws:iam::${var.account_id}:root"
},
Action = "sts:AssumeRole"
}
]
})

managed_policy_arns = [
"arn:aws:iam::aws:policy/AmazonEC2FullAccess",
"arn:aws:iam::aws:policy/AmazonVPCFullAccess",
"arn:aws:iam::aws:policy/AutoScalingFullAccess",
"arn:aws:iam::aws:policy/IAMFullAccess",
lsetiawan marked this conversation as resolved.
Show resolved Hide resolved
"arn:aws:iam::aws:policy/ReadOnlyAccess",
"arn:aws:iam::aws:policy/ResourceGroupsandTagEditorFullAccess",
]
}

resource "aws_iam_role_policy" "deploy_bucket_access" {
name = "${var.account_resource_prefix}_access_state_from_s3_new"
role = aws_iam_role.deploy.name
policy = jsonencode({
Version = "2012-10-17",
Statement = [
{
Effect = "Allow",
Action = [
"s3:GetObject",
"s3:PutObject",
"s3:DeleteObject",
"s3:ListBucket",
],
Resource = [
"${aws_s3_bucket.tf_state.arn}/*",
aws_s3_bucket.tf_state.arn,
],
},
],
})
}

resource "aws_iam_role_policy" "kms_key_access" {
name = "${var.account_resource_prefix}_kms_key_admin"
role = aws_iam_role.deploy.name
policy = jsonencode({
Version = "2012-10-17",
Statement = [
{
Effect = "Allow",
Action = [
"kms:TagResource",
"kms:UntagResource",
"kms:UpdateKeyDescription",
"kms:CreateKey",
"kms:CreateAlias",
],
Resource = "*",
},
],
})
}

resource "aws_iam_role_policy" "disallow_deploy_role_iam_user_operations" {
name = "${var.account_resource_prefix}_disallow_deploy_role_iam_user_operations"
role = aws_iam_role.deploy.name
policy = jsonencode({
Version = "2012-10-17",
Statement = [
{
Effect = "Deny",
Action = [
"iam:CreateUser",
"iam:DeleteUser",
"iam:UpdateUser",
"iam:CreateLoginProfile",
"iam:DeleteLoginProfile",
"iam:UpdateLoginProfile",
"iam:CreateAccessKey",
"iam:DeleteAccessKey",
"iam:UpdateAccessKey",
"iam:AttachUserPolicy",
"iam:DetachUserPolicy",
"iam:PutUserPolicy",
"iam:DeleteUserPolicy",
"iam:UpdateUserPolicy",
],
Resource = "*",
}
]
})
}

# user group
resource "aws_iam_group" "this" {
# TODO: decide if we want to use the account_resource_prefix here
name = var.ops_group_name
}

resource "aws_iam_group_policy" "assume_deploy" {
name = "assume-deploy-role"
group = aws_iam_group.this.name
policy = jsonencode({
Version = "2012-10-17",
Statement = [
{
Effect = "Allow",
Action = "sts:AssumeRole",
Resource = aws_iam_role.deploy.arn,
},
],
})
}

resource "aws_iam_group_policy_attachment" "readonly" {
group = aws_iam_group.this.name
policy_arn = "arn:aws:iam::aws:policy/ReadOnlyAccess"
}
5 changes: 5 additions & 0 deletions deployment/cloud/aws/account/terraform.tfvars
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
account_resource_prefix = "supportsphere"
account_additional_tags = {
"Project" = "Support Sphere"
}
account_id = "871683513797"
nikiburggraf marked this conversation as resolved.
Show resolved Hide resolved
21 changes: 21 additions & 0 deletions deployment/cloud/aws/account/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
variable "account_resource_prefix" {
description = "Prefix to apply to all account resources"
type = string
}

variable "account_id" {
description = "The AWS account ID"
type = string
}

variable "account_additional_tags" {
description = "Additional tags to apply to resources"
type = map(string)
default = {}
}

variable "ops_group_name" {
description = "The name of the admin group"
type = string
default = "ssec-eng"
}
Loading