POC: lift the homelab-grown nextcloud-mcp-server and nextcloud-mcp-deployer-role Terraform modules into this repo so external operators can consume them via a `git::` source. Includes a top-level README documenting the two-phase deploy flow (bootstrap deployer role with a copy-pasteable IAM policy, then assume the role to deploy the MCP server) and supports both in-VPC Qdrant and external/managed Qdrant modes. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
156 lines
4.2 KiB
Terraform
156 lines
4.2 KiB
Terraform
data "aws_iam_policy_document" "ecs_tasks_trust" {
|
|
statement {
|
|
actions = ["sts:AssumeRole"]
|
|
principals {
|
|
type = "Service"
|
|
identifiers = ["ecs-tasks.amazonaws.com"]
|
|
}
|
|
}
|
|
}
|
|
|
|
###
|
|
# Execution role — used by the ECS agent to pull the image, read secrets,
|
|
# and ship logs. Does not have application-level permissions.
|
|
|
|
resource "aws_iam_role" "execution" {
|
|
name = "${var.name}-execution"
|
|
path = "/ecs/"
|
|
assume_role_policy = data.aws_iam_policy_document.ecs_tasks_trust.json
|
|
}
|
|
|
|
resource "aws_iam_role_policy_attachment" "execution_managed" {
|
|
role = aws_iam_role.execution.name
|
|
policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"
|
|
}
|
|
|
|
data "aws_iam_policy_document" "execution_secrets" {
|
|
statement {
|
|
actions = ["secretsmanager:GetSecretValue"]
|
|
resources = [var.secret_arn]
|
|
}
|
|
}
|
|
|
|
resource "aws_iam_role_policy" "execution_secrets" {
|
|
name = "secrets-read"
|
|
role = aws_iam_role.execution.id
|
|
policy = data.aws_iam_policy_document.execution_secrets.json
|
|
}
|
|
|
|
###
|
|
# Task role — used by the running container. Needs Bedrock for embeddings
|
|
# and EFS client access to the two access points.
|
|
|
|
resource "aws_iam_role" "task" {
|
|
name = "${var.name}-task"
|
|
path = "/ecs/"
|
|
assume_role_policy = data.aws_iam_policy_document.ecs_tasks_trust.json
|
|
}
|
|
|
|
data "aws_iam_policy_document" "task_bedrock" {
|
|
statement {
|
|
actions = [
|
|
"bedrock:InvokeModel",
|
|
"bedrock:InvokeModelWithResponseStream",
|
|
]
|
|
resources = ["*"]
|
|
condition {
|
|
test = "StringEquals"
|
|
variable = "aws:RequestedRegion"
|
|
values = [data.aws_region.current.region]
|
|
}
|
|
}
|
|
}
|
|
|
|
resource "aws_iam_role_policy" "task_bedrock" {
|
|
name = "bedrock-invoke"
|
|
role = aws_iam_role.task.id
|
|
policy = data.aws_iam_policy_document.task_bedrock.json
|
|
}
|
|
|
|
data "aws_iam_policy_document" "task_efs" {
|
|
statement {
|
|
actions = [
|
|
"elasticfilesystem:ClientMount",
|
|
"elasticfilesystem:ClientWrite",
|
|
"elasticfilesystem:ClientRootAccess",
|
|
]
|
|
resources = [aws_efs_file_system.this.arn]
|
|
condition {
|
|
test = "StringEquals"
|
|
variable = "elasticfilesystem:AccessPointArn"
|
|
values = [
|
|
aws_efs_access_point.data.arn,
|
|
aws_efs_access_point.oauth.arn,
|
|
]
|
|
}
|
|
}
|
|
}
|
|
|
|
resource "aws_iam_role_policy" "task_efs" {
|
|
name = "efs-client"
|
|
role = aws_iam_role.task.id
|
|
policy = data.aws_iam_policy_document.task_efs.json
|
|
}
|
|
|
|
# ECS Exec support — lets us `aws ecs execute-command` into a running task
|
|
# for debugging without SSH.
|
|
data "aws_iam_policy_document" "task_exec" {
|
|
statement {
|
|
actions = [
|
|
"ssmmessages:CreateControlChannel",
|
|
"ssmmessages:CreateDataChannel",
|
|
"ssmmessages:OpenControlChannel",
|
|
"ssmmessages:OpenDataChannel",
|
|
]
|
|
resources = ["*"]
|
|
}
|
|
}
|
|
|
|
resource "aws_iam_role_policy" "task_exec" {
|
|
name = "ecs-exec"
|
|
role = aws_iam_role.task.id
|
|
policy = data.aws_iam_policy_document.task_exec.json
|
|
}
|
|
|
|
###
|
|
# Qdrant task role — only needs EFS access to its own access point and
|
|
# ECS Exec for debugging. Reuses the shared execution role.
|
|
|
|
resource "aws_iam_role" "qdrant_task" {
|
|
count = var.use_external_qdrant ? 0 : 1
|
|
name = "${local.qdrant_name}-task"
|
|
path = "/ecs/"
|
|
assume_role_policy = data.aws_iam_policy_document.ecs_tasks_trust.json
|
|
}
|
|
|
|
data "aws_iam_policy_document" "qdrant_task_efs" {
|
|
count = var.use_external_qdrant ? 0 : 1
|
|
statement {
|
|
actions = [
|
|
"elasticfilesystem:ClientMount",
|
|
"elasticfilesystem:ClientWrite",
|
|
"elasticfilesystem:ClientRootAccess",
|
|
]
|
|
resources = [aws_efs_file_system.this.arn]
|
|
condition {
|
|
test = "StringEquals"
|
|
variable = "elasticfilesystem:AccessPointArn"
|
|
values = [aws_efs_access_point.qdrant[0].arn]
|
|
}
|
|
}
|
|
}
|
|
|
|
resource "aws_iam_role_policy" "qdrant_task_efs" {
|
|
count = var.use_external_qdrant ? 0 : 1
|
|
name = "efs-client"
|
|
role = aws_iam_role.qdrant_task[0].id
|
|
policy = data.aws_iam_policy_document.qdrant_task_efs[0].json
|
|
}
|
|
|
|
resource "aws_iam_role_policy" "qdrant_task_exec" {
|
|
count = var.use_external_qdrant ? 0 : 1
|
|
name = "ecs-exec"
|
|
role = aws_iam_role.qdrant_task[0].id
|
|
policy = data.aws_iam_policy_document.task_exec.json
|
|
}
|