fleet/infrastructure/sandbox/PreProvisioner/main.tf
Zachary Winnerman 075ecf4a62
Add separate kms key for installers (#13786)
# Checklist for submitter

If some of the following don't apply, delete the relevant line.

- [ ] Changes file added for user-visible changes in `changes/` or
`orbit/changes/`.
See [Changes
files](https://fleetdm.com/docs/contributing/committing-changes#changes-files)
for more information.
- [ ] Documented any API changes (docs/Using-Fleet/REST-API.md or
docs/Contributing/API-for-contributors.md)
- [ ] Documented any permissions changes (docs/Using
Fleet/manage-access.md)
- [ ] Input data is properly validated, `SELECT *` is avoided, SQL
injection is prevented (using placeholders for values in statements)
- [ ] Added support on fleet's osquery simulator `cmd/osquery-perf` for
new osquery data ingestion features.
- [ ] Added/updated tests
- [ ] Manual QA for all new/changed functionality
  - For Orbit and Fleet Desktop changes:
- [ ] Manual QA must be performed in the three main OSs, macOS, Windows
and Linux.
- [ ] Auto-update manual QA, from released version of component to new
version (see [tools/tuf/test](../tools/tuf/test/README.md)).
2023-09-07 07:21:24 -04:00

415 lines
10 KiB
HCL

terraform {
required_providers {
docker = {
source = "kreuzwerker/docker"
version = "~> 2.16.0"
}
git = {
source = "paultyng/git"
version = "~> 0.1.0"
}
}
}
data "aws_region" "current" {}
data "aws_caller_identity" "current" {}
locals {
name = "preprovisioner"
full_name = "${var.prefix}-${local.name}"
}
resource "aws_cloudwatch_log_group" "main" {
name = local.full_name
kms_key_id = var.kms_key.arn
retention_in_days = 30
}
data "aws_iam_policy_document" "events-assume-role" {
statement {
actions = ["sts:AssumeRole"]
principals {
type = "Service"
identifiers = ["events.amazonaws.com"]
}
}
}
resource "aws_iam_role_policy_attachment" "events" {
role = aws_iam_role.events.id
policy_arn = aws_iam_policy.events.arn
}
resource "aws_iam_policy" "events" {
name = "${local.full_name}-events"
policy = data.aws_iam_policy_document.events.json
}
data "aws_iam_policy_document" "events" {
statement {
actions = ["ecs:RunTask"]
resources = [replace(aws_ecs_task_definition.main.arn, "/:\\d+$/", ":*"), replace(aws_ecs_task_definition.main.arn, "/:\\d+$/", "")]
condition {
test = "ArnLike"
variable = "ecs:cluster"
values = [var.ecs_cluster.arn]
}
}
statement {
actions = ["iam:PassRole"]
resources = ["*"]
condition {
test = "StringLike"
variable = "iam:PassedToService"
values = ["ecs-tasks.amazonaws.com"]
}
}
}
resource "aws_iam_role" "events" {
name = "${local.full_name}-events"
path = "/service-role/"
assume_role_policy = data.aws_iam_policy_document.events-assume-role.json
}
data "aws_iam_policy_document" "lambda-assume-role" {
statement {
actions = ["sts:AssumeRole"]
principals {
type = "Service"
identifiers = ["ecs-tasks.amazonaws.com"]
}
}
}
resource "aws_iam_role_policy_attachment" "lambda" {
role = aws_iam_role.lambda.id
policy_arn = aws_iam_policy.lambda.arn
}
resource "aws_iam_role_policy_attachment" "lambda-ecs" {
role = aws_iam_role.lambda.id
policy_arn = "arn:aws:iam::aws:policy/AmazonEKSFargatePodExecutionRolePolicy"
}
resource "aws_iam_policy" "lambda" {
name = "${var.prefix}-lambda"
policy = data.aws_iam_policy_document.lambda.json
}
data "aws_iam_policy_document" "lambda" {
statement {
actions = [
"dynamodb:List*",
"dynamodb:DescribeReservedCapacity*",
"dynamodb:DescribeLimits",
"dynamodb:DescribeTimeToLive"
]
resources = ["*"]
}
statement {
actions = [
"dynamodb:BatchGet*",
"dynamodb:DescribeStream",
"dynamodb:DescribeTable",
"dynamodb:Get*",
"dynamodb:Query",
"dynamodb:Scan",
"dynamodb:BatchWrite*",
"dynamodb:CreateTable",
"dynamodb:Delete*",
"dynamodb:Update*",
"dynamodb:PutItem"
]
resources = [var.dynamodb_table.arn]
}
statement {
actions = [ #tfsec:ignore:aws-iam-no-policy-wildcards
"kms:Encrypt*",
"kms:Decrypt*",
"kms:ReEncrypt*",
"kms:GenerateDataKey*",
"kms:Describe*"
]
resources = [aws_kms_key.ecr.arn, var.kms_key.arn, var.installer_kms_key.arn]
}
statement {
actions = [
"s3:*Object",
"s3:ListBucket",
]
resources = [
var.installer_bucket.arn,
"${var.installer_bucket.arn}/*"
]
}
statement {
actions = ["secretsmanager:GetSecretValue"]
resources = [aws_secretsmanager_secret.apple-signing-secrets.arn]
}
# TODO: limit this, this is for terraform
statement {
actions = ["*"]
resources = ["*"]
}
}
resource "aws_iam_role" "lambda" {
name = local.full_name
assume_role_policy = data.aws_iam_policy_document.lambda-assume-role.json
}
output "lambda_role" {
value = aws_iam_role.lambda
}
resource "aws_security_group" "lambda" {
name = local.full_name
description = "security group for ${local.full_name}"
vpc_id = var.vpc.vpc_id
egress {
description = "egress to all"
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
ipv6_cidr_blocks = ["::/0"]
}
}
data "aws_eks_cluster" "cluster" {
name = var.eks_cluster.eks_cluster_id
}
resource "aws_secretsmanager_secret" "apple-signing-secrets" {
name = "${local.full_name}-apple-signing-secrets"
kms_key_id = var.kms_key.id
recovery_window_in_days = 0
}
data "aws_secretsmanager_secret_version" "apple-signing-secrets" {
secret_id = aws_secretsmanager_secret.apple-signing-secrets.id
}
resource "aws_ecs_task_definition" "main" {
family = local.full_name
network_mode = "awsvpc"
requires_compatibilities = ["FARGATE"]
execution_role_arn = aws_iam_role.lambda.arn
task_role_arn = aws_iam_role.lambda.arn
cpu = 1024
memory = 4096
container_definitions = jsonencode(
[
{
name = local.name
image = docker_registry_image.main.name
mountPoints = []
volumesFrom = []
essential = true
networkMode = "awsvpc"
logConfiguration = {
logDriver = "awslogs"
options = {
awslogs-group = aws_cloudwatch_log_group.main.name
awslogs-region = data.aws_region.current.name
awslogs-stream-prefix = local.full_name
}
},
environment = concat([
{
name = "TF_VAR_mysql_secret"
value = var.mysql_secret.id
},
{
name = "TF_VAR_mysql_cluster_name"
value = var.eks_cluster.eks_cluster_id
},
{
name = "TF_VAR_eks_cluster"
value = var.eks_cluster.eks_cluster_id
},
{
name = "DYNAMODB_LIFECYCLE_TABLE"
value = var.dynamodb_table.id
},
{
name = "TF_VAR_lifecycle_table"
value = var.dynamodb_table.id
},
{
name = "TF_VAR_base_domain"
value = var.base_domain
},
{
name = "MAX_INSTANCES"
value = "500"
},
{
name = "QUEUED_INSTANCES"
value = "20"
},
{
name = "TF_VAR_redis_address"
value = "${var.redis_cluster.primary_endpoint_address}:6379"
},
{
name = "FLEET_BASE_URL"
value = var.base_domain
},
{
name = "INSTALLER_BUCKET"
value = var.installer_bucket.id
},
{
name = "TF_VAR_installer_bucket"
value = var.installer_bucket.id
},
{
name = "TF_VAR_installer_bucket_arn"
value = var.installer_bucket.arn
},
{
name = "TF_VAR_oidc_provider_arn"
value = var.oidc_provider_arn
},
{
name = "TF_VAR_oidc_provider"
value = var.oidc_provider
},
{
name = "TF_VAR_kms_key_arn"
value = var.installer_kms_key.arn
},
{
name = "TF_VAR_ecr_url"
value = var.ecr.repository_url
},
{
name = "TF_VAR_license_key"
value = var.license_key
},
{
name = "TF_VAR_apm_url"
value = var.apm_url
},
{
name = "TF_VAR_apm_token"
value = var.apm_token
},
]),
secrets = concat([
{
name = "MACOS_DEV_ID_CERTIFICATE_CONTENT"
valueFrom = "${aws_secretsmanager_secret.apple-signing-secrets.arn}:MACOS_DEV_ID_CERTIFICATE_CONTENT::"
},
{
name = "APP_STORE_CONNECT_API_KEY_ID"
valueFrom = "${aws_secretsmanager_secret.apple-signing-secrets.arn}:APP_STORE_CONNECT_API_KEY_ID::"
},
{
name = "APP_STORE_CONNECT_API_KEY_ISSUER"
valueFrom = "${aws_secretsmanager_secret.apple-signing-secrets.arn}:APP_STORE_CONNECT_API_KEY_ISSUER::"
},
{
name = "APP_STORE_CONNECT_API_KEY_CONTENT"
valueFrom = "${aws_secretsmanager_secret.apple-signing-secrets.arn}:APP_STORE_CONNECT_API_KEY_CONTENT::"
}
])
}
])
lifecycle {
create_before_destroy = true
}
}
resource "aws_kms_key" "ecr" {
deletion_window_in_days = 10
enable_key_rotation = true
}
resource "aws_ecr_repository" "main" {
name = "${var.prefix}-lambda"
image_tag_mutability = "IMMUTABLE"
image_scanning_configuration {
scan_on_push = true
}
encryption_configuration {
encryption_type = "KMS"
kms_key = aws_kms_key.ecr.arn
}
}
resource "random_uuid" "main" {
keepers = {
lambda = data.archive_file.main.output_sha
}
}
resource "local_file" "backend-config" {
content = templatefile("${path.module}/lambda/backend-template.conf",
{
remote_state = var.remote_state
})
filename = "${path.module}/lambda/deploy_terraform/backend.conf"
}
data "archive_file" "main" {
type = "zip"
output_path = "${path.module}/.lambda.zip"
source_dir = "${path.module}/lambda"
}
data "git_repository" "main" {
path = "${path.module}/../../../"
}
resource "docker_registry_image" "main" {
name = "${aws_ecr_repository.main.repository_url}:${data.git_repository.main.branch}-${random_uuid.main.result}"
keep_remotely = true
build {
context = "${path.module}/lambda/"
pull_parent = true
platform = "linux/amd64"
}
depends_on = [
local_file.backend-config
]
}
resource "aws_cloudwatch_event_rule" "main" {
name_prefix = var.prefix
schedule_expression = "rate(1 hour)"
is_enabled = true
}
resource "aws_cloudwatch_event_target" "main" {
rule = aws_cloudwatch_event_rule.main.name
arn = var.ecs_cluster.arn
role_arn = aws_iam_role.events.arn
ecs_target {
task_count = 1
task_definition_arn = aws_ecs_task_definition.main.arn
launch_type = "FARGATE"
network_configuration {
subnets = var.vpc.private_subnets
security_groups = [aws_security_group.lambda.id]
assign_public_ip = false
}
}
}