main
tf 354 lines 9.83 KB
Raw
1 locals {
2 cache_staging_domain = "cache-staging.nixos.org"
3 }
4
5 # This is the old bucket we want to archive.
6 module "cache-staging-202010" {
7 source = "./cache-bucket"
8 bucket_name = "nix-cache-staging"
9 providers = {
10 aws = aws.us
11 }
12 }
13
14 import {
15 to = module.cache-staging-202010.aws_s3_bucket_lifecycle_configuration.cache
16 id = "nix-cache-staging"
17 }
18
19 import {
20 to = module.cache-staging-202010.aws_s3_bucket_cors_configuration.cache
21 id = "nix-cache-staging"
22 }
23
24
25 # This is the new bucket we want to use in future.
26 module "cache-staging-202410" {
27 source = "./cache-bucket"
28 bucket_name = "nix-cache-staging-202410"
29 providers = {
30 # move the new bucket to EU
31 aws = aws
32 }
33 }
34
35 import {
36 to = module.cache-staging-202410.aws_s3_bucket_lifecycle_configuration.cache
37 id = "nix-cache-staging-202410"
38 }
39
40 import {
41 to = module.cache-staging-202410.aws_s3_bucket_cors_configuration.cache
42 id = "nix-cache-staging-202410"
43 }
44
45 # The fastly configuration below will first try the new bucket and than the old bucket.
46 # As demonstation we have two files in the buckets:
47 # $ curl https://cache-staging.nixos.org/new-cache │
48 # new
49 # $ curl https://cache-staging.nixos.org/old-cache
50 # old
51
52 resource "aws_s3_object" "old-cache-test-file" {
53 provider = aws.us
54 depends_on = [module.cache-staging-202010]
55
56 bucket = module.cache-staging-202010.bucket
57 content_type = "text/plain"
58 etag = filemd5("${path.module}/cache-staging/old-cache-test-file")
59 key = "old-cache"
60 source = "${path.module}/cache-staging/old-cache-test-file"
61 }
62 resource "aws_s3_object" "new-cache-test-file" {
63 provider = aws
64 depends_on = [module.cache-staging-202410]
65
66 bucket = module.cache-staging-202410.bucket
67 content_type = "text/plain"
68 etag = filemd5("${path.module}/cache-staging/new-cache-test-file")
69 key = "new-cache"
70 source = "${path.module}/cache-staging/new-cache-test-file"
71 }
72
73 resource "fastly_service_vcl" "cache-staging" {
74 name = local.cache_staging_domain
75 default_ttl = 86400
76
77 backend {
78 address = module.cache-staging-202010.bucket_regional_domain_name
79 auto_loadbalance = false
80 between_bytes_timeout = 10000
81 connect_timeout = 5000
82 error_threshold = 0
83 first_byte_timeout = 15000
84 max_conn = 200
85 name = "old_bucket"
86 port = 443
87 # For the old bucket we want to use Ashburn as our bucket is in us-east-1
88 shield = "iad-va-us"
89 ssl_cert_hostname = module.cache-staging-202010.bucket_regional_domain_name
90 ssl_check_cert = true
91 use_ssl = true
92 weight = 100
93 }
94
95 backend {
96 address = module.cache-staging-202410.bucket_regional_domain_name
97 auto_loadbalance = false
98 between_bytes_timeout = 10000
99 connect_timeout = 5000
100 error_threshold = 0
101 first_byte_timeout = 15000
102 max_conn = 200
103 name = "new_bucket"
104 port = 443
105 # The new bucket is in EU (eu-west-1)
106 shield = "dub-dublin-ie"
107 ssl_cert_hostname = module.cache-staging-202410.bucket_regional_domain_name
108 ssl_check_cert = true
109 use_ssl = true
110
111 # newer bucket has higher priority
112 weight = 200
113 }
114
115 # Temporarily disabled due to nix-index bugs: see https://github.com/nix-community/nix-index/issues/249
116 #request_setting {
117 # name = "Redirect HTTP to HTTPS"
118 # force_ssl = true
119 #}
120
121 condition {
122 name = "is-404"
123 priority = 0
124 statement = "beresp.status == 404"
125 type = "CACHE"
126 }
127
128 condition {
129 name = "Match /"
130 priority = 10
131 statement = "req.url ~ \"^/$\""
132 type = "REQUEST"
133 }
134
135 condition {
136 name = "Restarts > 0"
137 type = "REQUEST"
138 priority = 20
139 statement = "req.restarts > 0"
140 }
141
142 domain {
143 name = "cache-staging.nixos.org"
144 }
145
146 header {
147 name = "Landing page"
148 request_condition = "Match /"
149 ignore_if_set = false
150 priority = 10
151 type = "request"
152
153 action = "set"
154 destination = "url"
155 source = "\"/index.html\""
156
157 }
158
159 header {
160 name = "Use old bucket"
161 request_condition = "Restarts > 0"
162 ignore_if_set = false
163 priority = 20
164 type = "request"
165
166 action = "set"
167 destination = "backend"
168 source = "F_old_bucket"
169 }
170
171 # Clean headers for caching
172 header {
173 destination = "http.x-amz-request-id"
174 type = "cache"
175 action = "delete"
176 name = "remove x-amz-request-id"
177 }
178 header {
179 destination = "http.x-amz-version-id"
180 type = "cache"
181 action = "delete"
182 name = "remove x-amz-version-id"
183 }
184 header {
185 destination = "http.x-amz-id-2"
186 type = "cache"
187 action = "delete"
188 name = "remove x-amz-id-2"
189 }
190
191 # Enable Streaming Miss.
192 # https://docs.fastly.com/en/guides/streaming-miss
193 # https://github.com/NixOS/infra/issues/212#issuecomment-1187568233
194 header {
195 priority = 20
196 destination = "do_stream"
197 type = "cache"
198 action = "set"
199 name = "Enabling Streaming Miss"
200 source = "true"
201 }
202
203 # Allow CORS GET requests.
204 header {
205 destination = "http.access-control-allow-origin"
206 type = "response"
207 action = "set"
208 name = "CORS Allow"
209 source = "\"*\""
210 }
211
212 response_object {
213 name = "404-page"
214 cache_condition = "is-404"
215 content = "404"
216 content_type = "text/plain"
217 response = "Not Found"
218 status = 404
219 }
220
221 snippet {
222 name = "Variables for aws s3 auth"
223 type = "miss"
224 priority = 90
225 content = <<-EOT
226 declare local var.awsAccessKey STRING;
227 declare local var.awsSecretKey STRING;
228 declare local var.awsS3Bucket STRING;
229 declare local var.awsRegion STRING;
230 declare local var.awsS3Host STRING;
231
232 declare local var.canonicalHeaders STRING;
233 declare local var.signedHeaders STRING;
234 declare local var.canonicalRequest STRING;
235 declare local var.canonicalQuery STRING;
236 declare local var.stringToSign STRING;
237 declare local var.dateStamp STRING;
238 declare local var.signature STRING;
239 declare local var.scope STRING;
240 EOT
241 }
242
243 # Authenticate Fastly<->S3 requests. See Fastly documentation:
244 # https://docs.fastly.com/en/guides/amazon-s3#using-an-amazon-s3-private-bucket
245 snippet {
246 name = "Authenticate S3 requests for new bucket"
247 type = "miss"
248 priority = 100
249 content = templatefile("${path.module}/cache-staging/s3-authn.vcl", {
250 backend_name = "F_new_bucket"
251 aws_region = module.cache-staging-202410.region
252 bucket = module.cache-staging-202410.bucket
253 backend_domain = module.cache-staging-202410.bucket_domain_name
254 access_key = local.cache-iam.key
255 secret_key = local.cache-iam.secret
256 })
257 }
258
259 snippet {
260 name = "Authenticate S3 requests for old bucket"
261 type = "miss"
262 priority = 100
263 content = templatefile("${path.module}/cache-staging/s3-authn.vcl", {
264 backend_name = "F_old_bucket"
265 aws_region = module.cache-staging-202010.region
266 bucket = module.cache-staging-202010.bucket
267 backend_domain = module.cache-staging-202010.bucket_domain_name
268 access_key = local.cache-iam.key
269 secret_key = local.cache-iam.secret
270 })
271 }
272
273 snippet {
274 content = "set req.url = querystring.remove(req.url);"
275 name = "Remove all query strings"
276 priority = 50
277 type = "recv"
278 }
279
280
281 # Work around the 2GB size limit for large files
282 #
283 # See https://docs.fastly.com/en/guides/segmented-caching
284 snippet {
285 content = <<-EOT
286 if (req.url.path ~ "^/nar/") {
287 set req.enable_segmented_caching = true;
288 }
289 EOT
290 name = "Enable segment caching for NAR files"
291 priority = 60
292 type = "recv"
293 }
294
295 snippet {
296 name = "Fallback to old bucket on 403 or return 404"
297 type = "fetch"
298 priority = 90
299 content = <<-EOT
300 if (beresp.status == 403) {
301 if (req.backend == F_new_bucket) {
302 restart;
303 } else {
304 set beresp.status = 404;
305 }
306 }
307 EOT
308 }
309
310 # We will switch to this snipped once we retire the old bucket instead of the fallback above
311 #snippet {
312 # name = "Return 404 on 403"
313 # type = "fetch"
314 # priority = 90
315 # content = <<-EOT
316 # if (beresp.status == 403) {
317 # set beresp.status = 404;
318 # }
319 # EOT
320 #}
321
322 # Add a snippet to set a custom header based on the backend used
323 snippet {
324 name = "Set-Backend-Header"
325 type = "deliver"
326 priority = 70
327 content = <<-EOT
328 if (req.backend == F_old_bucket) {
329 set resp.http.X-Bucket = "${module.cache-staging-202010.bucket}";
330 } else if (req.backend == F_new_bucket) {
331 set resp.http.X-Bucket = "${module.cache-staging-202410.bucket}";
332 }
333 EOT
334 }
335
336 logging_s3 {
337 name = "${local.cache_staging_domain}-to-s3"
338 bucket_name = local.fastlylogs["bucket_name"]
339 compression_codec = "zstd"
340 domain = local.fastlylogs["s3_domain"]
341 format = local.fastlylogs["format"]
342 format_version = 2
343 path = "${local.cache_staging_domain}/"
344 period = local.fastlylogs["period"]
345 message_type = "blank"
346 s3_iam_role = local.fastlylogs["iam_role_arn"]
347 }
348 }
349
350 resource "fastly_tls_subscription" "cache-staging-2025-11" {
351 domains = [for domain in fastly_service_vcl.cache-staging.domain : domain.name]
352 configuration_id = local.fastly_tls13_quic_configuration_id
353 certificate_authority = "lets-encrypt"
354 }