-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathvariables.tf
More file actions
528 lines (454 loc) · 21.3 KB
/
Copy pathvariables.tf
File metadata and controls
528 lines (454 loc) · 21.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
variable "environment_name" {
type = string
description = "friendly qualifier to distinguish resources created by this terraform configuration other Terraform deployments, (eg, 'prod', 'dev', etc)"
default = "psoxy"
validation {
condition = can(regex("^[a-zA-Z][a-zA-Z0-9-_ ]*$", var.environment_name))
error_message = "The `environment_name` must start with a letter, can contain alphanumeric characters, hyphens, underscores, and spaces, and must end with a letter or number."
}
validation {
condition = !can(regex("^(?i)(aws|ssm)", var.environment_name))
error_message = "The `environment_name` cannot start with 'aws' or 'ssm', as this will name your AWS resources with prefixes that displease the AMZN overlords."
}
}
variable "aws_account_id" {
type = string
description = "id of aws account in which to provision your AWS infra"
validation {
condition = can(regex("^\\d{12}$", var.aws_account_id))
error_message = "The aws_account_id value should be 12-digit numeric string."
}
}
variable "aws_assume_role_arn" {
type = string
description = "ARN of role Terraform should assume when provisioning your infra. (can be `null` if your CLI is auth'd as the right user/role)"
default = null
}
variable "aws_region" {
type = string
description = "default region in which to provision your AWS infra"
default = "us-east-1"
}
variable "new_relic_account_id" {
type = string
description = "**beta** New Relic account ID to enable New Relic instrumentation. If set, this will auto-configure the NEW_RELIC_ACCOUNT_ID and NEW_RELIC_LAMBDA_HANDLER environment variables for proxied lambdas."
default = null
}
variable "iam_roles_permissions_boundary" {
type = string
description = "*beta* ARN of the permissions boundary to attach to IAM roles created by this module."
default = null
}
variable "default_tags" {
type = map(string)
description = "Tags to apply to all resources created by this configuration. See https://registry.terraform.io/providers/hashicorp/aws/latest/docs#default_tags for more info."
default = {}
}
variable "aws_ssm_param_root_path" {
type = string
description = "path under which SSM parameters created by this module will be created; NOTE: shouldn't be necessary to use this is you're following recommended approach of using dedicated AWS account for deployment"
default = ""
validation {
condition = length(var.aws_ssm_param_root_path) == 0 || length(regexall("/", var.aws_ssm_param_root_path)) == 0 || startswith(var.aws_ssm_param_root_path, "/")
error_message = "The aws_ssm_param_root_path value must be fully qualified (begin with `/`) if it contains any `/` characters."
}
}
variable "aws_secrets_manager_path" {
type = string
description = "**beta** path under which Secrets Manager secrets will be created"
default = ""
validation {
condition = length(var.aws_secrets_manager_path) == 0 || length(regexall("/", var.aws_secrets_manager_path)) == 0 || startswith(var.aws_secrets_manager_path, "/")
error_message = "The `aws_secrets_manager_path` value must be fully qualified (begin with `/`) if it contains any `/` characters."
}
}
variable "secrets_store_implementation" {
type = string
description = "one of 'aws_ssm_parameter_store' (default) or 'aws_secrets_manager'"
default = "aws_ssm_parameter_store"
validation {
error_message = "The `secrets_store_implementation` value must be one of 'aws_ssm_parameter_store' or 'aws_secrets_manager'."
condition = var.secrets_store_implementation == "aws_ssm_parameter_store" || var.secrets_store_implementation == "aws_secrets_manager"
}
}
variable "project_aws_kms_key_arn" {
type = string
description = "AWS KMS key ARN to use to encrypt all AWS components created by this Terraform configuration that support CMEKs. NOTE: Terraform must be authenticated as an AWS principal authorized to encrypt/decrypt with this key."
default = null
validation {
condition = var.project_aws_kms_key_arn == null || can(regex("^arn:aws:kms:.*:\\d{12}:key\\/.*$", var.project_aws_kms_key_arn))
error_message = "The project_aws_kms_key_arn value should be null or a valid an AWS KMS key ARN."
}
}
variable "aws_lambda_execution_role_policy_arn" {
type = string
description = "*beta* The ARN of policy to attach to the lambda execution role, if you want one other than the default. (usually, AWSLambdaBasicExecutionRole)."
default = null
}
variable "worklytics_host" {
type = string
description = "host of worklytics instance where tenant resides. (e.g. intl.worklytics.co for prod; but may differ for dev/staging)"
default = "intl.worklytics.co"
}
variable "caller_gcp_service_account_ids" {
type = list(string)
description = "ids of GCP service accounts allowed to send requests to the proxy (eg, unique ID of the SA of your Worklytics instance)"
default = []
validation {
condition = alltrue([
for i in var.caller_gcp_service_account_ids : (length(regexall("^\\d{21}$", i)) > 0)
])
error_message = "The values of caller_gcp_service_account_ids should be 21-digit numeric strings."
}
}
variable "caller_aws_arns" {
type = list(string)
description = "ARNs of AWS accounts allowed to send requests to the proxy (eg, arn:aws:iam::914358739851:root)"
default = []
validation {
condition = alltrue([
# see https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_iam-quotas.html
# sources suggest limit of 64 chars for role names, but not clear if that includes paths so not checking it
for i in var.caller_aws_arns : (length(regexall("^arn:aws:iam::\\d{12}:((role|user)\\/)?[A-Za-z0-9/=,.@_-]+$", i)) > 0)
])
error_message = "The values of caller_aws_arns should be AWS Resource Names, something like 'arn:aws:iam::123123123123:root', 'arn:aws:iam::123123123123:user/ExampleUser', 'arn:aws:iam:123123123123:role/TestRole'" # for testing; can remove once prod-ready
}
}
variable "test_aws_principal_arns" {
type = list(string)
description = "AWS principal ARNs allowed to test the deployment. When null and provision_testing_infra is true, defaults to the IAM principal running Terraform."
default = null
nullable = true
}
variable "connector_display_name_suffix" {
type = string
description = "suffix to append to display_names of connector SAs; helpful to distinguish between various ones in testing/dev scenarios"
default = ""
}
variable "psoxy_base_dir" {
type = string
description = "the path where your psoxy repo resides. Preferably a full path, /home/user/repos/, avoid tilde (~) shortcut to $HOME"
validation {
condition = can(regex(".*\\/$", var.psoxy_base_dir))
error_message = "The psoxy_base_dir value should end with a slash."
}
}
variable "deployment_bundle" {
type = string
description = "path to deployment bundle to use (if not provided, will build one)"
default = null
validation {
condition = var.deployment_bundle == null || var.deployment_bundle != ""
error_message = "`deployment_bundle`, if non-null, must be non-empty string."
}
}
variable "force_bundle" {
type = bool
description = "whether to force build of deployment bundle, even if it already exists for this proxy version"
default = false
}
variable "provision_testing_infra" {
type = bool
description = "whether to provision infra needed to support testing of deployment"
default = false
}
variable "install_test_tool" {
type = bool
description = "whether to install the test tool (can be 'false' if Terraform not running from a machine where you intend to run tests of your Psoxy deployment)"
default = true
}
variable "general_environment_variables" {
type = map(string)
description = "environment variables to add for all connectors"
default = {}
validation {
condition = !contains(keys(var.general_environment_variables), "IS_DEVELOPMENT_MODE")
error_message = "Use 'non_production_connectors' to flag connectors as non-production, rather than passing `IS_DEVELOPMENT_MODE` environment variable."
}
validation {
condition = !contains(keys(var.general_environment_variables), "PSEUDONYMIZE_APP_IDS")
error_message = "Use 'pseudonymize_app_ids' to set value of PSEUDONYMIZE_APP_IDS environment variable for all sources, rather than passing it as a general environment variable."
}
validation {
condition = !contains(keys(var.general_environment_variables), "EMAIL_CANONICALIZATION")
error_message = "Use 'email_canonicalization' to set value of EMAIL_CANONICALIZATION environment variable for all sources, rather than passing it as a general environment variable."
}
}
variable "pseudonymize_app_ids" {
type = string
description = "if set, will set value of PSEUDONYMIZE_APP_IDS environment variable to this value for all sources"
default = true
}
variable "email_canonicalization" {
type = string
description = "defines how email address are processed prior to hashing, hence which are considered 'canonically equivalent'; one of 'STRICT' (default and most standard compliant) or 'IGNORE_DOTS' (probably most in line with user expectations)"
default = "IGNORE_DOTS"
}
variable "enabled_connectors" {
type = list(string)
description = "list of ids of connectors to enabled; see modules/worklytics-connector-specs"
}
variable "non_production_connectors" {
type = list(string)
description = "connector ids in this list will be in development mode (not for production use)"
default = []
}
variable "bulk_input_expiration_days" {
type = number
description = "Number of days after which objects in the bucket will expire. This could be as low as 1 day; longer aids debugging of issues."
default = 30
}
variable "bulk_sanitized_expiration_days" {
type = number
description = "Number of days after which objects in the bucket will expire. This should match the amount of historical data you wish for Worklytics to analyze (eg, typically multiple years)."
default = 1805 # 5 years; intent is 'forever', but some upperbound in case bucket is forgotten
}
variable "custom_api_connectors" {
type = map(object({
source_kind = string
source_auth_strategy = string
target_host = string
oauth_scopes_needed = optional(list(string), [])
environment_variables = optional(map(string), {})
enable_async_processing = optional(bool, false)
example_api_calls = optional(list(string), [])
example_api_requests = optional(list(object({
method = optional(string, "GET")
path = string
content_type = optional(string, "application/json")
body = optional(string, null)
headers = optional(map(string), {})
})), [])
example_api_calls_user_to_impersonate = optional(string)
secured_variables = optional(list(object({
name = string
value = optional(string)
writable = optional(bool, false)
lockable = optional(bool, false)
sensitive = optional(bool, true)
description = optional(string)
value_managed_by_tf = optional(bool, true)
})),
[])
settings_to_provide = optional(map(string), {})
rules_file = optional(string, null)
}))
description = "map of custom API connectors to provision"
default = {
# "custom-api" = {
# source_kind = "my-custom-api"
# source_auth_strategy = "bearer"
# target_host = "api.example.com"
# example_api_calls = ["/v1/users"]
# secured_variables = [
# { name = "API_KEY" }
# ]
# }
}
}
variable "custom_api_connector_rules" {
type = map(string)
description = "map of connector id --> YAML file with custom rules"
default = {}
}
variable "use_api_gateway_v2" {
type = bool
description = "**alpha** whether to use API Gateway (v2); if not lambdas exposed via function URLs, unless VPC is configured."
default = false
}
variable "log_retention_days" {
type = number
description = "Number of days to retain logs in CloudWatch."
default = 7
}
variable "provision_bucket_public_access_block" {
type = bool
description = "Whether to provision public_access_block resources on all buckets; defaults to 'true', but can be 'false' if you have organizational control policies that do this at a higher level."
default = true
}
variable "custom_bulk_connectors" {
type = map(object({
source_kind = string
display_name = optional(string, "Custom Bulk Connector")
worklytics_connector_id = optional(string, "bulk-import-psoxy")
worklytics_connector_name = optional(string, "Custom Bulk Data via Psoxy")
rules_file = optional(string)
rules = optional(object({
pseudonymFormat = optional(string, "URL_SAFE_TOKEN")
columnsToRedact = optional(list(string)) # columns to remove from CSV
columnsToInclude = optional(list(string)) # if you prefer to include only an explicit list of columns, rather than redacting those you don't want
columnsToPseudonymize = optional(list(string)) # columns to pseudonymize
columnsToPseudonymizeIfPresent = optional(list(string)) # columns to pseudonymize when present; omit if absent
columnsToDuplicate = optional(map(string)) # columns to create copy of; name --> new name
columnsToRename = optional(map(string)) # columns to rename: original name --> new name; renames applied BEFORE pseudonymization
fieldsToTransform = optional(map(object({
newName = string
transforms = optional(list(map(string)), [])
})), {})
}))
memory_size_mb = optional(number, null)
settings_to_provide = optional(map(string), {})
example_file = optional(string)
example_files = optional(list(string), [])
}))
description = "specs of custom bulk connectors to create"
default = {
# "custom-survey" = {
# source_kind = "survey"
# rules = {
# columnsToRedact = []
# columnsToPseudonymize = [
# "employee_id", # primary key
# # "employee_email", # if exists
# ]
# }
# }
}
}
variable "custom_bulk_connector_rules" {
type = map(object({
pseudonymFormat = optional(string, "URL_SAFE_TOKEN")
columnsToRedact = optional(list(string), []) # columns to remove from CSV
columnsToInclude = optional(list(string)) # if you prefer to include only an explicit list of columns, rather than redacting those you don't want
columnsToPseudonymize = optional(list(string), []) # columns to pseudonymize
columnsToPseudonymizeIfPresent = optional(list(string), null)
columnsToDuplicate = optional(map(string)) # columns to create copy of; name --> new name
columnsToRename = optional(map(string)) # columns to rename: original name --> new name; renames applied BEFORE pseudonymization
fieldsToTransform = optional(map(object({
newName = string
transforms = optional(list(map(string)), [])
})))
}))
description = "map of connector id --> rules object"
default = {
# hris = {
# columnsToRedact = []
# columnsToPseudonymize = [
# "EMPLOYEE_ID",
# "EMPLOYEE_EMAIL",
# "MANAGER_ID",
# "MANAGER_EMAIL"
# ]
# columnsToRename = {
# # original --> new
# "workday_id" = "employee_id"
# }
# columnsToInclude = [
# ]
}
}
variable "custom_bulk_connector_arguments" {
type = map(object({
memory_size_mb = optional(number)
}))
description = "map of connector id --> arguments object, to override defaults for bulk connector instances"
default = {}
}
variable "custom_side_outputs" {
type = map(object({
ORIGINAL = optional(string, null),
SANITIZED = optional(string, null),
}))
description = "*ALPHA* map of connector id --> side output targets"
default = {}
}
variable "webhook_collectors" {
type = map(object({
worklytics_connector_id = optional(string, "work-data-generic-psoxy")
worklytics_connector_name = optional(string, "Workplace Metadata via Psoxy")
display_name = optional(string, "Webhooks Collected via Psoxy")
source_kind = optional(string, "work-event") # source kind for this webhook collector, used for labeling and categorization
rules_file = string
provision_auth_key = optional(object({ # whether to provision auth keys for webhook collector; if not provided, will not provision any
rotation_days = optional(number, null) # null means no rotation; if > 0, will rotate every N days
key_spec = optional(string, "RSA_2048") # RSA_2048, RSA_3072, or RSA_4096; defaults to RSA_2048, which should be sufficient this use-case
}), null)
auth_public_keys = optional(list(string), []) # list of public keys to use for verifying webhook signatures; if empty AND no auth keys provision, no app-level auth will be done
allow_origins = optional(list(string), ["*"]) # list of origins to allow for CORS, eg 'https://my-app.com'; if you want to allow all origins, use ['*'] (the default)
output_path_prefix = optional(string, "") # optional path prefix to prepend to webhook output files in bucket (e.g., 'events_', 'webhooks/')
keep_warm_instances = optional(number, null) # if set to 1+, keeps that many Lambda instances warm to eliminate cold starts; adds cost (~$11/month per instance) but improves reliability
example_payload_file = optional(string, null) # path to example payload file to use for testing; if provided, will be used in the test script
example_identity = optional(string, null) # example identity to use for testing; if provided, will be used to test the collector
}))
default = {}
description = "map of webhook collector id --> webhook collector configuration"
}
variable "lookup_table_builders" {
type = map(object({
input_connector_id = string
sanitized_accessor_role_names = list(string)
rules = object({
pseudonymFormat = optional(string, "URL_SAFE_TOKEN")
columnsToRedact = optional(list(string), [])
columnsToInclude = optional(list(string))
columnsToPseudonymize = optional(list(string), [])
columnsToDuplicate = optional(map(string))
columnsToRename = optional(map(string))
})
compress_output = optional(bool)
}))
default = {
# "hris-lookup" = {
# input_connector_id = "hris",
# sanitized_accessor_role_names = [
# # ADD LIST OF NAMES OF YOUR AWS ROLES WHICH CAN READ LOOKUP TABLE
# ],
# rules = {
# pseudonym_format = "URL_SAFE_TOKEN"
# columnsToRedact = [
# "employee_email",
# "manager_id",
# "manager_email",
# ]
# columnsToPseudonymize = [
# "employee_id", # primary key
# ]
# columnsToDuplicate = {
# "employee_id" = "employee_id_orig"
# }
# columnsToRename = {}
# columnsToInclude = null
# }
#
# }
}
}
variable "allowed_data_access_ip_blocks" {
description = <<-EOT
IPs or CIDR blocks allowed to make data access requests. On AWS, enforces at IAM (assume-role aws:SourceIp) and in the proxy. Use null (default) for no restriction. If set, the list must contain at least one value. See docs/configuration/ip-allowlisting.md.
EOT
type = list(string)
nullable = true
default = null
validation {
condition = var.allowed_data_access_ip_blocks == null || try(length(var.allowed_data_access_ip_blocks) > 0, false)
error_message = "allowed_data_access_ip_blocks must be null (allow all) or a non-empty list; an empty list is invalid."
}
}
variable "allowed_webhook_ip_blocks" {
description = <<-EOT
IPs or CIDR blocks allowed to send webhooks. On AWS, enforces at IAM (webhook-test-caller aws:SourceIp) and in the proxy. Use null (default) for no restriction. If set, the list must contain at least one value. See docs/configuration/ip-allowlisting.md.
EOT
type = list(string)
nullable = true
default = null
validation {
condition = var.allowed_webhook_ip_blocks == null || try(length(var.allowed_webhook_ip_blocks) > 0, false)
error_message = "allowed_webhook_ip_blocks must be null (allow all) or a non-empty list; an empty list is invalid."
}
}
variable "connector_settings" {
type = map(string)
default = {}
description = "Connector-specific settings."
}
variable "todos_as_outputs" {
type = bool
description = "whether to render TODOs as outputs (former useful if you're using Terraform Cloud/Enterprise, or somewhere else where the filesystem is not readily accessible to you)"
default = false
}
variable "todos_as_local_files" {
type = bool
description = "whether to render TODOs as flat files"
default = true
}