|
1 | 1 | locals { |
2 | | - data_source_backends = ["local", "remote", "s3", "azurerm", "gcs"] |
3 | | - is_data_source_backend = contains(local.data_source_backends, local.backend_type) |
| 2 | + custom_backends = ["none", "bypass", "static"] |
| 3 | + is_data_source_backend = !contains(local.custom_backends, local.backend_type) |
4 | 4 |
|
5 | 5 | remote_workspace = var.workspace != null ? var.workspace : local.workspace |
6 | 6 | ds_backend = local.is_data_source_backend ? local.backend_type : "none" |
7 | 7 | ds_workspace = local.ds_backend == "none" ? null : local.remote_workspace |
8 | 8 |
|
| 9 | + # The `privileged` flag is no longer used in the Cloud Posse reference architecture, but is maintained for compatibility. |
| 10 | + # This was and is only supported for the S3 backend. |
| 11 | + # |
| 12 | + # When the `privileged` flag is set to `true`, the user running Terraform is considered privileged and therefore |
| 13 | + # does not need to assume a different role to access the S3 backend. |
| 14 | + # |
| 15 | + # This is accomplished by removing any profile or role ARN settings from the configuration. |
| 16 | + s3_privileged_backend = { for k, v in local.backend : k => v if !contains(["profile", "role_arn", "assume_role", "assume_role_with_web_identity"], k) } |
| 17 | + |
| 18 | + # Workaround for the fact that the 2 different backends can be different types, |
| 19 | + # but both results of a conditional must be the same type. |
| 20 | + s3_backend = { |
| 21 | + # normal, not privileged |
| 22 | + false = local.backend |
| 23 | + # privileged |
| 24 | + true = local.s3_privileged_backend |
| 25 | + } |
| 26 | + |
| 27 | + # Customize certain configurations. Otherwise we will just use whatever was configured in the stack. |
9 | 28 | ds_configurations = { |
10 | 29 | # If no valid configuration is found for the backend datasource, provide a dummy one. |
11 | 30 | none = { |
12 | 31 | path = "${path.module}/dummy-remote-state.json" |
13 | 32 | } |
14 | 33 |
|
15 | | - # Note: If the local backend has a relative path, it will be resolved |
16 | | - # relative to the current working directory, which is usually a root module |
17 | | - # referencing the remote state. However, when the local backend is created, |
18 | | - # the current working directory is the directory where the target root module |
19 | | - # is defined. This will likely cause the lookup to fail unless the current |
20 | | - # and target root module directories are in the same directory. |
21 | | - # |
22 | | - # Both path and workspace_dir are optional. |
23 | | - local = local.ds_backend != "local" ? null : merge({}, |
24 | | - try(length(lookup(local.backend, "path", "")), 0) > 0 ? { |
25 | | - path = lookup(local.backend, "path", "") |
26 | | - } : {}, |
27 | | - try(length(lookup(local.backend, "workspace_dir", "")), 0) > 0 ? { |
28 | | - workspace_dir = lookup(local.backend, "workspace_dir", "") |
29 | | - } : {} |
30 | | - ) |
31 | | - |
32 | | - remote = local.ds_backend != "remote" ? null : { |
33 | | - organization = local.backend.organization |
34 | | - |
| 34 | + remote = merge(local.backend, { |
35 | 35 | workspaces = { |
36 | 36 | name = local.remote_workspace |
37 | 37 | } |
38 | | - } |
39 | | - |
40 | | - s3 = local.ds_backend != "s3" ? null : { |
41 | | - encrypt = local.backend.encrypt |
42 | | - bucket = local.backend.bucket |
43 | | - key = local.backend.key |
44 | | - dynamodb_table = local.backend.dynamodb_table |
45 | | - region = local.backend.region |
46 | | - |
47 | | - # NOTE: component types |
48 | | - # Privileged components are those that require elevated (root-level) permissions to provision and access their remote state. |
49 | | - # For example: `tfstate-backend`, `account`, `account-map`, `account-settings`, `iam-primary`. |
50 | | - # Privileged components are usually provisioned during cold-start (when we don't have any IAM roles provisioned yet) by using an admin user credentials. |
51 | | - # To access the remote state of privileged components, the caller needs to have permissions to access the backend and the remote state without assuming roles. |
52 | | - # Regular components, on the other hand, don't require root-level permissions and are provisioned and their remote state is accessed by assuming IAM roles (or using profiles). |
53 | | - # For example: `vpc`, `eks`, `rds` |
54 | | - |
55 | | - # NOTE: global `backend` config |
56 | | - # The global `backend` config should be declared in a global YAML stack config file (e.g. `globals.yaml`) |
57 | | - # where all stacks can import it and have access to it (note that the global `backend` config is organization-wide and will not change after cold-start). |
58 | | - # The global `backend` config in the global config file should always have the `role_arn` or `profile` specified (added after the cold-start). |
59 | | - |
60 | | - # NOTE: components `backend` config |
61 | | - # The `backend` portion for each individual component should be declared in a catalog file (e.g. `stacks/catalog/<component>.yaml`) |
62 | | - # along with all the default values for a component. |
63 | | - # The `privileged` attribute should always be declared in the `backend` portion for each individual component in the catalog. |
64 | | - # Top-level stacks where a component is provisioned import the component's catalog (the default values and the component's backend config portion) and can override the default values. |
65 | | - |
66 | | - # NOTE: `cold-start` |
67 | | - # During cold-start we don't have any IAM roles provisioned yet, so we use an admin user credentials to provision the privileged components. |
68 | | - # The `privileged` attribute for the privileged components should be set to `true` in the components' catalog, |
69 | | - # and the privileged components should be provisioned using an admin user credentials. |
70 | | - |
71 | | - # NOTE: after `cold-start` |
72 | | - # After the privileged components (including the primary IAM roles) are provisioned, we update the global `backend` config in the global config file |
73 | | - # to add the IAM role or profile to access the backend (after this, the global `backend` config should never change). |
74 | | - # For some privileged components we can change the `privileged` attribute in the YAML config from `true` to `false` |
75 | | - # to allow the regular components to access their remote state (e.g. we set the `privileged` attribute to `false` in the `account-map` component |
76 | | - # since we use `account-map` in almost all regular components. |
77 | | - # For each regular component, set the `privileged` attribute to `false` in the components' portion of `backend` config (in `stacks/catalog/<component>.yaml`) |
78 | | - |
79 | | - # Advantages: |
80 | | - # The global `backend` config is specified just once in the global config file, IAM role or profile is added to it after the cold start, |
81 | | - # and after that the global `backend` config never changed. |
82 | | - # We can make a component privileged or not any time by just updating its `privileged` attribute in the component's catalog file. |
83 | | - # We can change a component's `backend` portion any time without touching/affection the backend configs of all other components (e.g. when we add a new |
84 | | - # component, we don't touch the `globals.yaml` file at all, and we don't update the component's `role_arn` and `profile` settings). |
85 | | - |
86 | | - # Use the role to access the remote state if the component is not privileged and `role_arn` is specified |
87 | | - role_arn = !coalesce(try(local.backend.privileged, null), var.privileged) && contains(keys(local.backend), "role_arn") ? local.backend.role_arn : null |
88 | | - |
89 | | - # Use the profile to access the remote state if the component is not privileged and `profile` is specified |
90 | | - profile = !coalesce(try(local.backend.privileged, null), var.privileged) && contains(keys(local.backend), "profile") ? local.backend.profile : null |
91 | | - |
92 | | - workspace_key_prefix = local.workspace_key_prefix |
93 | | - |
94 | | - # S3-compatible backend for Oracle |
95 | | - # source: https://docs.oracle.com/en-us/iaas/Content/API/SDKDocs/terraformUsingObjectStore.htm#s3 |
96 | | - skip_region_validation = try(local.backend.skip_region_validation, null) |
97 | | - skip_credentials_validation = try(local.backend.skip_credentials_validation, null) |
98 | | - skip_requesting_account_id = try(local.backend.skip_requesting_account_id, null) |
99 | | - use_path_style = try(local.backend.use_path_style, null) |
100 | | - force_path_style = try(local.backend.force_path_style, null) |
101 | | - skip_metadata_api_check = try(local.backend.skip_metadata_api_check, null) |
102 | | - skip_s3_checksum = try(local.backend.skip_s3_checksum, null) |
103 | | - endpoints = try(local.backend.endpoints, null) |
104 | | - endpoint = try(local.backend.endpoint, null) |
105 | | - } |
106 | | - |
107 | | - azurerm = local.ds_backend != "azurerm" ? null : { |
108 | | - resource_group_name = local.backend.resource_group_name |
109 | | - storage_account_name = local.backend.storage_account_name |
110 | | - container_name = local.backend.container_name |
111 | | - key = local.backend.key |
112 | | - } |
113 | | - |
114 | | - gcs = local.ds_backend != "gcs" ? null : { |
115 | | - bucket = local.backend.bucket |
116 | | - prefix = local.backend.prefix |
117 | | - } |
| 38 | + }) |
118 | 39 |
|
| 40 | + s3 = local.s3_backend[var.privileged] |
119 | 41 | } # ds_configurations |
120 | 42 |
|
121 | 43 | } |
122 | 44 |
|
123 | 45 | data "terraform_remote_state" "data_source" { |
124 | 46 | count = var.bypass ? 0 : 1 |
125 | 47 |
|
| 48 | + # Use a dummy local backend when the real backend is not supported by the data source |
126 | 49 | backend = local.ds_backend == "none" ? "local" : local.ds_backend |
127 | 50 | workspace = local.ds_workspace |
128 | | - config = local.ds_configurations[local.ds_backend] |
129 | | - defaults = var.defaults |
| 51 | + # If nothing needs to be customized, just use whatever was configured in the stack |
| 52 | + config = lookup(local.ds_configurations, local.ds_backend, local.backend) |
| 53 | + defaults = var.defaults |
130 | 54 | } |
0 commit comments