eleven / messenger Public

Clone
git clone https://amadan.net/eleven/messenger

Plain git — no account needed to clone.

Download

Download this file

1# 🤖 Production instance-hibernation state (issue #550 Part 4 v2 on the real
2# fleet): the bucket activator-managed instances park in, and the router
3# box's scoped credentials for it. Separate from the fleet-backup bucket —
4# hibernation's embedded Litestream owns each managed DB's replication
5# (deploy/fleet-backup.sh excludes those hosts; two replicators on one WAL
6# would fight over checkpointing).
7
8resource "aws_s3_bucket" "prod_instances" {
9 bucket = "eleven-prod-instances-${local.account_id}"
10}
11
12resource "aws_s3_bucket_versioning" "prod_instances" {
13 bucket = aws_s3_bucket.prod_instances.id
14
15 versioning_configuration {
16 status = "Enabled"
17 }
18}
19
20resource "aws_s3_bucket_lifecycle_configuration" "prod_instances" {
21 bucket = aws_s3_bucket.prod_instances.id
22
23 rule {
24 id = "expire-noncurrent-14d"
25 status = "Enabled"
26
27 filter {}
28
29 noncurrent_version_expiration {
30 noncurrent_days = 14
31 }
32 }
33}
34
35resource "aws_s3_bucket_public_access_block" "prod_instances" {
36 bucket = aws_s3_bucket.prod_instances.id
37
38 block_public_acls = true
39 block_public_policy = true
40 ignore_public_acls = true
41 restrict_public_buckets = true
42}
43
44# TLS-only: deny any request arriving over plain HTTP. The activator's
45# embedded Litestream and the stats publisher both speak HTTPS already —
46# this turns that assumption into policy. A deny-only statement grants
47# nothing public, so it attaches fine under the full access block above.
48data "aws_iam_policy_document" "prod_instances_tls_only" {
49 statement {
50 sid = "DenyInsecureTransport"
51 effect = "Deny"
52 actions = ["s3:*"]
53 resources = [
54 aws_s3_bucket.prod_instances.arn,
55 "${aws_s3_bucket.prod_instances.arn}/*",
56 ]
57
58 principals {
59 type = "*"
60 identifiers = ["*"]
61 }
62
63 condition {
64 test = "Bool"
65 variable = "aws:SecureTransport"
66 values = ["false"]
67 }
68 }
69}
70
71resource "aws_s3_bucket_policy" "prod_instances" {
72 bucket = aws_s3_bucket.prod_instances.id
73 policy = data.aws_iam_policy_document.prod_instances_tls_only.json
74}
75
76# The router's activator credentials: object rw + version listing (the wake
77# path restores, the lease CASes, sweepers may prune) on this bucket only.
78# Key minted by hand, lives in the router's env — never in tofu state.
79resource "aws_iam_user" "activator_prod" {
80 name = "activator-prod"
81}
82
83data "aws_iam_policy_document" "activator_prod" {
84 statement {
85 sid = "ListProdInstances"
86 actions = ["s3:ListBucket", "s3:ListBucketVersions"]
87 resources = [aws_s3_bucket.prod_instances.arn]
88 }
89
90 statement {
91 sid = "ReadWriteProdInstanceObjects"
92 actions = [
93 "s3:GetObject",
94 "s3:PutObject",
95 "s3:DeleteObject",
96 "s3:DeleteObjectVersion",
97 ]
98 resources = ["${aws_s3_bucket.prod_instances.arn}/*"]
99 }
100}
101
102resource "aws_iam_user_policy" "activator_prod" {
103 name = "activator-prod-instances-bucket"
104 user = aws_iam_user.activator_prod.name
105 policy = data.aws_iam_policy_document.activator_prod.json
106}
107
108output "prod_instances_bucket" {
109 value = aws_s3_bucket.prod_instances.bucket
110}
111