rails_template_18f 2.0.0 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +13 -0
  3. data/Gemfile.lock +9 -7
  4. data/lib/generators/rails_template18f/active_storage/active_storage_generator.rb +4 -3
  5. data/lib/generators/rails_template18f/auditree/auditree_generator.rb +36 -6
  6. data/lib/generators/rails_template18f/auditree/templates/gitlab/auditree.yml.tt +48 -0
  7. data/lib/generators/rails_template18f/circleci/templates/circleci/config.yml.tt +12 -2
  8. data/lib/generators/rails_template18f/cloud_gov_config/cloud_gov_config_generator.rb +0 -8
  9. data/lib/generators/rails_template18f/cloud_gov_config/templates/app/models/cloud_gov_config.rb +6 -7
  10. data/lib/generators/rails_template18f/cloud_gov_config/templates/spec/models/cloud_gov_config_spec.rb +13 -19
  11. data/lib/generators/rails_template18f/github_actions/github_actions_generator.rb +0 -4
  12. data/lib/generators/rails_template18f/github_actions/templates/github/workflows/deploy-production.yml +3 -1
  13. data/lib/generators/rails_template18f/github_actions/templates/github/workflows/deploy-staging.yml +3 -1
  14. data/lib/generators/rails_template18f/github_actions/templates/github/workflows/terraform-production.yml +3 -1
  15. data/lib/generators/rails_template18f/github_actions/templates/github/workflows/terraform-staging.yml +3 -1
  16. data/lib/generators/rails_template18f/gitlab_ci/gitlab_ci_generator.rb +138 -0
  17. data/lib/generators/rails_template18f/gitlab_ci/templates/gitlab/node.yml.tt +11 -0
  18. data/lib/generators/rails_template18f/gitlab_ci/templates/gitlab/rails.yml +75 -0
  19. data/lib/generators/rails_template18f/gitlab_ci/templates/gitlab/ruby.yml +7 -0
  20. data/lib/generators/rails_template18f/gitlab_ci/templates/gitlab/terraform.yml +33 -0
  21. data/lib/generators/rails_template18f/gitlab_ci/templates/gitlab-ci.yml.tt +213 -0
  22. data/lib/generators/rails_template18f/oscal/oscal_generator.rb +15 -1
  23. data/lib/generators/rails_template18f/oscal/templates/bin/trestle.tt +10 -1
  24. data/lib/generators/rails_template18f/oscal/templates/gitlab/trestle.yml.tt +29 -0
  25. data/lib/generators/rails_template18f/public_egress/public_egress_generator.rb +16 -32
  26. data/lib/generators/rails_template18f/sidekiq/templates/config/initializers/redis.rb +1 -1
  27. data/lib/generators/rails_template18f/terraform/templates/gitlab_bootstrap/apply.sh +25 -0
  28. data/lib/generators/rails_template18f/terraform/templates/gitlab_bootstrap/main.tf.tt +98 -0
  29. data/lib/generators/rails_template18f/terraform/templates/gitlab_bootstrap/setup_shadowenv.sh +59 -0
  30. data/lib/generators/rails_template18f/terraform/templates/s3_bootstrap/common/templates/backend_config.tftpl +6 -0
  31. data/lib/generators/rails_template18f/terraform/templates/s3_bootstrap/common/templates/bot_secrets.tftpl +5 -0
  32. data/lib/generators/rails_template18f/terraform/templates/s3_bootstrap/common/users.auto.tfvars +5 -0
  33. data/lib/generators/rails_template18f/terraform/templates/{full_bootstrap → s3_bootstrap/full}/main.tf.tt +4 -11
  34. data/lib/generators/rails_template18f/terraform/templates/{sandbox_bootstrap → s3_bootstrap/sandbox}/main.tf.tt +3 -3
  35. data/lib/generators/rails_template18f/terraform/templates/terraform/.shadowenv.d/.gitignore +3 -0
  36. data/lib/generators/rails_template18f/terraform/templates/terraform/README.md.tt +38 -36
  37. data/lib/generators/rails_template18f/terraform/templates/terraform/app.tf.tt +1 -6
  38. data/lib/generators/rails_template18f/terraform/templates/terraform/main.tf.tt +30 -19
  39. data/lib/generators/rails_template18f/terraform/templates/terraform/production.tfvars.tt +3 -0
  40. data/lib/generators/rails_template18f/terraform/templates/terraform/providers.tf.tt +4 -24
  41. data/lib/generators/rails_template18f/terraform/templates/terraform/staging.tfvars.tt +5 -5
  42. data/lib/generators/rails_template18f/terraform/templates/terraform/terraform.sh.tt +40 -55
  43. data/lib/generators/rails_template18f/terraform/templates/terraform/variables.tf.tt +11 -12
  44. data/lib/generators/rails_template18f/terraform/terraform_generator.rb +78 -6
  45. data/lib/rails_template18f/version.rb +1 -1
  46. data/template.rb +50 -25
  47. data/templates/{pa11yci.js → pa11yci.js.tt} +5 -0
  48. metadata +28 -20
  49. data/lib/generators/rails_template18f/terraform/templates/terraform/bootstrap/templates/backend_config.tftpl +0 -8
  50. data/lib/generators/rails_template18f/terraform/templates/terraform/sandbox_bot/main.tf +0 -74
  51. data/lib/generators/rails_template18f/terraform/templates/terraform/sandbox_bot/run.sh +0 -17
  52. /data/lib/generators/rails_template18f/{github_actions → oscal}/templates/github/workflows/assemble-ssp.yml.tt +0 -0
  53. /data/lib/generators/rails_template18f/{github_actions → oscal}/templates/github/workflows/validate-ssp.yml +0 -0
  54. /data/lib/generators/rails_template18f/terraform/templates/{terraform/bootstrap/templates → gitlab_bootstrap}/bot_secrets.tftpl +0 -0
  55. /data/lib/generators/rails_template18f/terraform/templates/{terraform/bootstrap → gitlab_bootstrap}/users.auto.tfvars +0 -0
  56. /data/lib/generators/rails_template18f/terraform/templates/{terraform/bootstrap → s3_bootstrap/common}/apply.sh +0 -0
  57. /data/lib/generators/rails_template18f/terraform/templates/{full_bootstrap → s3_bootstrap/full}/imports.tf.tftpl +0 -0
  58. /data/lib/generators/rails_template18f/terraform/templates/{sandbox_bootstrap → s3_bootstrap/sandbox}/imports.tf.tftpl +0 -0
@@ -0,0 +1,33 @@
1
+ # Shared setup helpers for terraform jobs
2
+ .terraform:setup:
3
+ stage: deploy
4
+ inherit:
5
+ default: false
6
+ image:
7
+ name: "hashicorp/terraform"
8
+ entrypoint: ["sh"]
9
+ variables:
10
+ CF_API_URL: https://api.fr.cloud.gov
11
+ TF_STATE_NAME: staging
12
+ TF_HTTP_ADDRESS: ${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/terraform/state/${TF_STATE_NAME}
13
+ TF_HTTP_LOCK_ADDRESS: ${TF_HTTP_ADDRESS}/lock
14
+ TF_HTTP_UNLOCK_ADDRESS: ${TF_HTTP_ADDRESS}/lock
15
+ TF_HTTP_USERNAME: gitlab-ci-token
16
+ TF_HTTP_PASSWORD: ${CI_JOB_TOKEN}
17
+ dependencies: []
18
+ before_script:
19
+ - cd terraform
20
+ - terraform init
21
+ rules:
22
+ - if: $CI_PIPELINE_SOURCE != "schedule"
23
+
24
+ .terraform:variables:staging:
25
+ dependencies: null
26
+ variables:
27
+ CF_USER: $CF_USERNAME
28
+
29
+ .terraform:variables:production:
30
+ dependencies: null
31
+ variables:
32
+ CF_USER: $CF_USERNAME
33
+ TF_STATE_NAME: "production"
@@ -0,0 +1,213 @@
1
+ # Note that environment variables can be set in several places
2
+ # See https://docs.gitlab.com/ee/ci/variables/#cicd-variable-precedence
3
+
4
+ workflow:
5
+ rules:
6
+ - if: $CI_PIPELINE_SOURCE == 'merge_request_event'
7
+ - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
8
+ - if: $CI_COMMIT_BRANCH == "production"
9
+
10
+ stages:
11
+ - build
12
+ - test
13
+ - scan
14
+ - deploy
15
+
16
+ variables:
17
+ POSTGRES_DB: <%= app_name %>_test
18
+ POSTGRES_PASSWORD: not-actually-secret
19
+ POSTGRES_VERSION: <%= postgres_version %>
20
+ RUBY_VERSION: <%= RUBY_VERSION %>
21
+
22
+ include:
23
+ - local: ".gitlab/ruby.yml"
24
+ - local: ".gitlab/node.yml"
25
+ - local: ".gitlab/rails.yml"
26
+ - local: ".gitlab/terraform.yml"
27
+
28
+ default:
29
+ image: "ruby:${RUBY_VERSION}"
30
+ before_script:
31
+ - !reference [.setup-ruby]
32
+ cache:
33
+ - !reference [.cache-dependencies, cache]
34
+
35
+ build-project:
36
+ stage: build
37
+ extends: [.cache-dependencies, .setup-languages]
38
+ cache:
39
+ policy: pull-push
40
+ script:
41
+ - !reference [.bundle-install]
42
+ - !reference [.yarn-install]
43
+ - bin/rake assets:precompile
44
+ artifacts:
45
+ expire_in: 1 hour
46
+ paths:
47
+ - app/assets/builds
48
+ - public/assets
49
+ rules:
50
+ - if: $CI_PIPELINE_SOURCE != "schedule"
51
+
52
+ brakeman-scan:
53
+ stage: test
54
+ script:
55
+ - bin/brakeman --no-pager --ensure-ignore-notes -f sarif -o output.sarif.json
56
+ artifacts:
57
+ when: always
58
+ expose_as: "Brakeman results"
59
+ paths:
60
+ - output.sarif.json
61
+
62
+ dependency_scanning:
63
+ stage: test
64
+ extends: .setup-languages
65
+ script:
66
+ - bin/rake bundler:audit
67
+ - bin/rake yarn:audit
68
+ - gem install cyclonedx-ruby
69
+ - cyclonedx-ruby -p . -o ruby_bom.xml
70
+ artifacts:
71
+ expose_as: "Ruby SBOM"
72
+ paths:
73
+ - ruby_bom.xml
74
+
75
+ rspec:
76
+ stage: test
77
+ extends: .setup-project
78
+ script:
79
+ - bundle exec rspec
80
+ rules:
81
+ - if: $CI_PIPELINE_SOURCE != "schedule"
82
+
83
+ pa11y_scan:
84
+ stage: scan
85
+ extends: .run-server
86
+ script:
87
+ - !reference [.install-puppet-deps]
88
+ - yarn run pa11y-ci -c pa11yci.js
89
+ rules:
90
+ - if: $CI_PIPELINE_SOURCE != "schedule"
91
+
92
+ owasp_scan:
93
+ extends: .owasp:setup
94
+ script:
95
+ - /zap/zap-baseline.py -t http://localhost:3000 -c zap.conf -I -r zap_report.html
96
+ rules:
97
+ - if: $CI_PIPELINE_SOURCE != "schedule"
98
+
99
+ owasp_daily_scan:
100
+ extends: .owasp:setup
101
+ script:
102
+ - /zap/zap-full-scan.py -t http://localhost:3000 -c zap.conf -I -r zap_report.html
103
+ rules:
104
+ - if: $CI_PIPELINE_SOURCE == "schedule"
105
+
106
+ terraform:fmt:
107
+ stage: test
108
+ extends: .terraform:setup
109
+ script:
110
+ - terraform fmt -check -recursive .
111
+
112
+ terraform:validate:
113
+ stage: test
114
+ extends: .terraform:setup
115
+ script:
116
+ - terraform validate
117
+
118
+ terraform:assets:staging:
119
+ extends: .assets:builder
120
+ cache:
121
+ - !reference [.cache-dependencies, cache]
122
+ - key: staging-assets
123
+ unprotect: true
124
+ paths:
125
+ - public/assets
126
+ - app/assets/builds
127
+ policy: $CACHE_POLICY
128
+ variables:
129
+ RAILS_ENV: staging
130
+ rules:
131
+ - if: $CI_PIPELINE_SOURCE == "schedule"
132
+ when: never
133
+ - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
134
+ variables:
135
+ CACHE_POLICY: pull-push
136
+ - variables:
137
+ CACHE_POLICY: pull
138
+ <% if terraform_manage_spaces? %>
139
+ terraform:assets:production:
140
+ extends: .assets:builder
141
+ cache:
142
+ - !reference [.cache-dependencies, cache]
143
+ - key: production-assets
144
+ paths:
145
+ - public/assets
146
+ - app/assets/builds
147
+ policy: $CACHE_POLICY
148
+ variables:
149
+ RAILS_ENV: production
150
+ rules:
151
+ - if: $CI_COMMIT_BRANCH == "production"
152
+ variables:
153
+ CACHE_POLICY: pull-push
154
+ - if: $CI_PIPELINE_SOURCE != "schedule"
155
+ variables:
156
+ CACHE_POLICY: pull
157
+ <% end %>
158
+ terraform:plan:staging:
159
+ extends:
160
+ - .terraform:setup
161
+ - .terraform:variables:staging
162
+ needs: ["terraform:assets:staging"]
163
+ script:
164
+ - apk add zip
165
+ - terraform plan -out=staging_plan.out -var-file=staging.tfvars -var rails_master_key=$RAILS_MASTER_KEY -var cf_user=$CF_USERNAME
166
+ artifacts:
167
+ paths:
168
+ - terraform/staging_plan.out
169
+ - terraform/dist
170
+
171
+ terraform:apply:staging:
172
+ extends:
173
+ - .terraform:setup
174
+ - .terraform:variables:staging
175
+ needs:
176
+ - terraform:plan:staging
177
+ - terraform:assets:staging
178
+ script:
179
+ - apk add zip
180
+ - terraform apply -var-file=staging.tfvars -var rails_master_key=$RAILS_MASTER_KEY -var cf_user=$CF_USERNAME staging_plan.out
181
+ rules:
182
+ - if: $CI_PIPELINE_SOURCE == "schedule"
183
+ when: never
184
+ - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
185
+ <% if terraform_manage_spaces? %>
186
+ terraform:plan:production:
187
+ extends:
188
+ - .terraform:setup
189
+ - .terraform:variables:production
190
+ needs: ["terraform:assets:production"]
191
+ script:
192
+ - apk add zip
193
+ - terraform plan -out=production_plan.out -var-file=production.tfvars -var rails_master_key=$PRODUCTION_RAILS_MASTER_KEY -var cf_user=$CF_USERNAME
194
+ artifacts:
195
+ paths:
196
+ - terraform/production_plan.out
197
+ - terraform/dist
198
+
199
+ terraform:apply:production:
200
+ extends:
201
+ - .terraform:setup
202
+ - .terraform:variables:production
203
+ needs:
204
+ - terraform:plan:production
205
+ - terraform:assets:production
206
+ script:
207
+ - apk add zip
208
+ - terraform apply -var-file=production.tfvars -var rails_master_key=$PRODUCTION_RAILS_MASTER_KEY -var cf_user=$CF_USERNAME production_plan.out
209
+ rules:
210
+ - if: $CI_PIPELINE_SOURCE == "schedule"
211
+ when: never
212
+ - if: $CI_COMMIT_BRANCH == "production"
213
+ when: manual<% end %>
@@ -49,6 +49,16 @@ module RailsTemplate18f
49
49
  end
50
50
  end
51
51
 
52
+ def copy_gitlab_ci
53
+ if use_gitlab_ci?
54
+ directory "gitlab", ".gitlab"
55
+ if file_exists? ".gitlab-ci.yml"
56
+ insert_into_file ".gitlab-ci.yml", " - local: \".gitlab/trestle.yml\"\n", after: /^include:\n/
57
+ insert_into_file ".gitlab-ci.yml", " TRESTLE_VERSION: #{docker_trestle_tag}\n", after: /^variables:\n/
58
+ end
59
+ end
60
+ end
61
+
52
62
  def update_readme
53
63
  if file_content("README.md").match?("## Documentation")
54
64
  insert_into_file "README.md", readme_contents, after: "## Documentation\n"
@@ -85,13 +95,17 @@ module RailsTemplate18f
85
95
  end
86
96
 
87
97
  def docker_trestle_tag
88
- options[:tag].present? ? options[:tag] : "20240912"
98
+ options[:tag].present? ? options[:tag] : "20250603"
89
99
  end
90
100
 
91
101
  def use_github_actions?
92
102
  options[:ci] == "github" || file_exists?(".github/workflows")
93
103
  end
94
104
 
105
+ def use_gitlab_ci?
106
+ options[:ci] == "gitlab" || file_exists?(".gitlab-ci.yml")
107
+ end
108
+
95
109
  def readme_contents
96
110
  content = <<~README
97
111
 
@@ -2,8 +2,17 @@
2
2
 
3
3
  trestle_tag="<%= docker_trestle_tag %>"
4
4
 
5
+ if [ "$1" = "-h" ]; then
6
+ echo """
7
+ Usage: $0 [-h] [CMD [CMD ARGS]]
8
+
9
+ CMD defaults to 'bash'
10
+ """
11
+ exit 0
12
+ fi
13
+
5
14
  command="bash"
6
- if [ "$1" != "" ]; then
15
+ if [ -n "$1" ]; then
7
16
  command=$1
8
17
  shift 1
9
18
  fi
@@ -0,0 +1,29 @@
1
+ .trestle:setup:
2
+ inherit:
3
+ default: false
4
+ image: "ghcr.io/gsa-tts/trestle:${TRESTLE_VERSION}"
5
+ before_script:
6
+ - cd doc/compliance/oscal
7
+ - export PATH="/app/bin:$PATH"
8
+
9
+ validate_ssp:
10
+ extends: .trestle:setup
11
+ stage: test
12
+ script:
13
+ - validate-ssp-json
14
+ rules:
15
+ - if: $CI_PIPELINE_SOURCE != "schedule"
16
+
17
+ assemble_ssp:
18
+ extends: .trestle:setup
19
+ stage: deploy
20
+ script:
21
+ - trestle assemble -n <%= app_name %> system-security-plan
22
+ - render-ssp
23
+ artifacts:
24
+ expose_as: "<%= app_name %> SSPP"
25
+ paths:
26
+ - doc/compliance/oscal/dist/system-security-plans/<%= app_name %>.json
27
+ - doc/compliance/oscal/ssp-render/<%= app_name %>_ssp.md
28
+ rules:
29
+ - if: $CI_PIPELINE_SOURCE != "schedule"
@@ -41,24 +41,6 @@ EOT
41
41
  EOT
42
42
  end
43
43
 
44
- def setup_terraform_provider
45
- insert_into_file file_path("terraform/providers.tf"), after: "required_providers {\n" do
46
- <<-EOT
47
- cloudfoundry-community = {
48
- source = "cloudfoundry-community/cloudfoundry"
49
- version = "0.53.1"
50
- }
51
- EOT
52
- end
53
- append_to_file file_path("terraform/providers.tf"), <<~EOT
54
- provider "cloudfoundry-community" {
55
- api_url = "https://api.fr.cloud.gov"
56
- user = var.cf_user
57
- password = var.cf_password
58
- }
59
- EOT
60
- end
61
-
62
44
  def setup_proxy_vars
63
45
  create_file ".profile", <<~EOP unless file_exists?(".profile")
64
46
  ##
@@ -117,18 +99,19 @@ EOB
117
99
  <<~EOT
118
100
 
119
101
  module "egress_space" {
120
- source = "github.com/gsa-tts/terraform-cloudgov//cg_space?ref=v2.1.0"
102
+ source = "github.com/gsa-tts/terraform-cloudgov//cg_space?ref=v2.3.0"
121
103
 
122
104
  cf_org_name = local.cf_org_name
123
105
  cf_space_name = "${var.cf_space_name}-egress"
124
- allow_ssh = var.allow_space_ssh
106
+ allow_ssh = var.allow_ssh
125
107
  deployers = local.space_deployers
126
108
  developers = var.space_developers
109
+ auditors = var.space_auditors
127
110
  security_group_names = ["public_networks_egress"]
128
111
  }
129
112
 
130
113
  module "egress_proxy" {
131
- source = "github.com/gsa-tts/terraform-cloudgov//egress_proxy?ref=v2.1.0"
114
+ source = "github.com/gsa-tts/terraform-cloudgov//egress_proxy?ref=v2.3.0"
132
115
 
133
116
  cf_org_name = local.cf_org_name
134
117
  cf_egress_space = module.egress_space.space
@@ -139,17 +122,18 @@ EOB
139
122
  }
140
123
 
141
124
  resource "cloudfoundry_network_policy" "egress_routing" {
142
- provider = cloudfoundry-community
143
- policy {
144
- source_app = cloudfoundry_app.app.id
145
- destination_app = module.egress_proxy.app_id
146
- port = "61443"
147
- }
148
- policy {
149
- source_app = cloudfoundry_app.app.id
150
- destination_app = module.egress_proxy.app_id
151
- port = "8080"
152
- }
125
+ policies = [
126
+ {
127
+ source_app = cloudfoundry_app.app.id
128
+ destination_app = module.egress_proxy.app_id
129
+ port = module.egress_proxy.https_port
130
+ },
131
+ {
132
+ source_app = cloudfoundry_app.app.id
133
+ destination_app = module.egress_proxy.app_id
134
+ port = module.egress_proxy.http_port
135
+ }
136
+ ]
153
137
  }
154
138
 
155
139
  resource "cloudfoundry_service_instance" "egress_proxy_credentials" {
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  Rails.application.config.to_prepare do
4
- redis_url = CloudGovConfig.dig "aws-elasticache-redis", "credentials", "uri"
4
+ redis_url = CloudGovConfig.new.dig "aws-elasticache-redis", "credentials", "uri"
5
5
  if redis_url.present?
6
6
  Sidekiq.configure_server do |config|
7
7
  config.redis = {url: redis_url, ssl: true}
@@ -0,0 +1,25 @@
1
+ #!/usr/bin/env bash
2
+
3
+ if ! command -v terraform &> /dev/null
4
+ then
5
+ echo "terraform must be installed before running this script"
6
+ exit 1
7
+ fi
8
+
9
+ if [ -z "$GITLAB_PROJECT_ID" ] || [ -z "$GITLAB_HOSTNAME" ]; then
10
+ echo "GITLAB_PROJECT_ID or GITLAB_HOSTNAME has not been set. Run ./setup_shadowenv.sh first"
11
+ exit 1
12
+ fi
13
+
14
+ set -e
15
+
16
+ # ensure we're logged in via cli
17
+ cf spaces &> /dev/null || cf login -a api.fr.cloud.gov --sso
18
+
19
+ tf_state_address="https://$GITLAB_HOSTNAME/api/v4/projects/$GITLAB_PROJECT_ID/terraform/state/bootstrap"
20
+ terraform init \
21
+ -backend-config="address=$tf_state_address" \
22
+ -backend-config="lock_address=$tf_state_address/lock" \
23
+ -backend-config="unlock_address=$tf_state_address/lock"
24
+
25
+ terraform apply "$@"
@@ -0,0 +1,98 @@
1
+ terraform {
2
+ required_version = "~> 1.10"
3
+ required_providers {
4
+ cloudfoundry = {
5
+ source = "cloudfoundry/cloudfoundry"
6
+ version = "~> 1.7"
7
+ }
8
+ }
9
+ backend "http" {
10
+ lock_method = "POST"
11
+ unlock_method = "DELETE"
12
+ retry_wait_min = 5
13
+ }
14
+ }
15
+ # empty config will let terraform borrow cf-cli's auth
16
+ provider "cloudfoundry" {}
17
+
18
+ locals {
19
+ org_name = "<%= cloud_gov_organization %>"
20
+ space_name = "<%= terraform_manage_spaces? ? "#{ cloud_gov_production_space }-mgmt" : cloud_gov_staging_space %>"
21
+ }
22
+
23
+ data "cloudfoundry_org" "org" {
24
+ name = local.org_name
25
+ }
26
+ <% if terraform_manage_spaces? %>
27
+ variable "terraform_users" {
28
+ type = set(string)
29
+ description = "The list of developer emails and service account usernames who should be granted access to retrieve state bucket credentials"
30
+
31
+ validation {
32
+ condition = length(var.terraform_users) > 0
33
+ error_message = "terraform_users must include at least the current user calling apply.sh"
34
+ }
35
+ }
36
+
37
+ module "mgmt_space" {
38
+ source = "github.com/gsa-tts/terraform-cloudgov//cg_space?ref=v2.3.0"
39
+
40
+ cf_org_name = local.org_name
41
+ cf_space_name = local.space_name
42
+ developers = var.terraform_users
43
+ }
44
+ <% else %>
45
+ data "cloudfoundry_space" "space" {
46
+ name = local.space_name
47
+ org = data.cloudfoundry_org.org.id
48
+ }
49
+ <% end %>
50
+ data "cloudfoundry_service_plans" "cg_service_account" {
51
+ name = "<%= terraform_manage_spaces? ? "space-auditor" : "space-deployer" %>"
52
+ service_offering_name = "cloud-gov-service-account"
53
+ }
54
+ locals {
55
+ sa_service_name = "<%= app_name %>-cicd-deployer"
56
+ sa_key_name = "cicd-deployer-access-key"
57
+ sa_bot_credentials = jsondecode(data.cloudfoundry_service_credential_binding.runner_sa_key.credential_bindings.0.credential_binding).credentials
58
+ sa_cf_username = nonsensitive(local.sa_bot_credentials.username)
59
+ sa_cf_password = local.sa_bot_credentials.password
60
+ }
61
+ resource "cloudfoundry_service_instance" "runner_service_account" {
62
+ name = local.sa_service_name
63
+ type = "managed"
64
+ service_plan = data.cloudfoundry_service_plans.cg_service_account.service_plans.0.id<% if terraform_manage_spaces? %>
65
+ space = module.mgmt_space.space_id
66
+ depends_on = [module.mgmt_space]<% else %>
67
+ space = data.cloudfoundry_space.space.id<% end %>
68
+ }
69
+ resource "cloudfoundry_service_credential_binding" "runner_sa_key" {
70
+ name = local.sa_key_name
71
+ service_instance = cloudfoundry_service_instance.runner_service_account.id
72
+ type = "key"
73
+ }
74
+ data "cloudfoundry_service_credential_binding" "runner_sa_key" {
75
+ name = local.sa_key_name
76
+ service_instance = cloudfoundry_service_instance.runner_service_account.id
77
+ depends_on = [cloudfoundry_service_credential_binding.runner_sa_key]
78
+ }<% if terraform_manage_spaces? %>
79
+ data "cloudfoundry_user" "sa_user" {
80
+ name = local.sa_cf_username
81
+ }
82
+ resource "cloudfoundry_org_role" "sa_org_manager" {
83
+ user = data.cloudfoundry_user.sa_user.users.0.id
84
+ type = "organization_manager"
85
+ org = data.cloudfoundry_org.org.id
86
+ }<% end %>
87
+
88
+ resource "local_sensitive_file" "bot_secrets_file" {
89
+ filename = "${path.module}/secrets.cicd.tfvars"
90
+ file_permission = "0600"
91
+
92
+ content = templatefile("${path.module}/bot_secrets.tftpl", {
93
+ service_name = local.sa_service_name,
94
+ key_name = local.sa_key_name,
95
+ username = local.sa_cf_username,
96
+ password = local.sa_cf_password
97
+ })
98
+ }
@@ -0,0 +1,59 @@
1
+ #!/usr/bin/env bash
2
+ #
3
+ # Setup .shadowenv.d/ files for terraform configuration
4
+
5
+ set -e
6
+
7
+ # ensure we're operating with the correct relative paths
8
+ cd `dirname "$0"`
9
+
10
+ shadowenv trust && eval "$(shadowenv hook)"
11
+
12
+ ans=""
13
+ prompt_ans() {
14
+ local prompt="$1"
15
+ local default="$2"
16
+ if [ -n "$default" ]; then
17
+ prompt="$prompt (default: $default)"
18
+ fi
19
+ read -r -p "$prompt: " ans
20
+ }
21
+
22
+ prompt_ans "GitLab hostname" "${GITLAB_HOSTNAME:=gsa.gitlab-dedicated.us}"
23
+ if [ -n "$ans" ]; then
24
+ GITLAB_HOSTNAME="$ans"
25
+ fi
26
+
27
+ prompt_ans "GitLab project id" "$GITLAB_PROJECT_ID"
28
+ if [ -n "$ans" ]; then
29
+ GITLAB_PROJECT_ID="$ans"
30
+ fi
31
+
32
+ if [ ! -d ../.shadowenv.d ]; then
33
+ mkdir ../.shadowenv.d
34
+ fi
35
+
36
+ cat <<EOF > ../.shadowenv.d/100_gitlab_project.lisp
37
+ (provide "gitlab-backend-config")
38
+ (env/set "GITLAB_HOSTNAME" "$GITLAB_HOSTNAME")
39
+ (env/set "GITLAB_PROJECT_ID" "$GITLAB_PROJECT_ID")
40
+ EOF
41
+
42
+ prompt_ans "GitLab username" "$TF_HTTP_USERNAME"
43
+ if [ -n "$ans" ]; then
44
+ TF_HTTP_USERNAME=$ans
45
+ fi
46
+ if [ -z "$TF_HTTP_PASSWORD" ]; then
47
+ prompt_ans "GitLab PAT (with api scope)"
48
+ else
49
+ prompt_ans "GitLab PAT (with api scope, Leave blank to re-use existing PAT)"
50
+ fi
51
+ if [ -n "$ans" ]; then
52
+ TF_HTTP_PASSWORD=$ans
53
+ fi
54
+
55
+ cat <<EOF > ../.shadowenv.d/500_tf_backend_secrets.lisp
56
+ (provide "tf-backend-secrets")
57
+ (env/set "TF_HTTP_USERNAME" "$TF_HTTP_USERNAME")
58
+ (env/set "TF_HTTP_PASSWORD" "$TF_HTTP_PASSWORD")
59
+ EOF
@@ -0,0 +1,6 @@
1
+ (provide "terraform-backend-config")
2
+ (env/set "S3_BUCKET_NAME" "${creds.bucket}")
3
+ (env/set "AWS_ACCESS_KEY_ID" "${creds.access_key_id}")
4
+ (env/set "AWS_SECRET_ACCESS_KEY" "${creds.secret_access_key}")
5
+ ; not a secret, but setting it here enables the aws cli to work when in the terraform directory
6
+ (env/set "AWS_REGION" "${creds.region}")
@@ -0,0 +1,5 @@
1
+ # Generated via bootstrap module. Remove this file when finished
2
+ # credentials for service "${service_name}"/"${key_name}"
3
+
4
+ cf_user = "${username}"
5
+ cf_password = "${password}"
@@ -0,0 +1,5 @@
1
+ terraform_users = [
2
+ # add your terraform_users list here: example values:
3
+ # "team.member@gsa.gov",
4
+ # "cf_user-guid-value-for-space-developer-service-account",
5
+ ]
@@ -3,7 +3,7 @@ terraform {
3
3
  required_providers {
4
4
  cloudfoundry = {
5
5
  source = "cloudfoundry/cloudfoundry"
6
- version = "1.2.0"
6
+ version = "~> 1.7"
7
7
  }
8
8
  }
9
9
  }
@@ -36,7 +36,7 @@ locals {
36
36
  s3_plan_name = "basic"
37
37
  }
38
38
  module "mgmt_space" {
39
- source = "github.com/gsa-tts/terraform-cloudgov//cg_space?ref=v2.1.0"
39
+ source = "github.com/gsa-tts/terraform-cloudgov//cg_space?ref=v2.3.0"
40
40
 
41
41
  cf_org_name = local.org_name
42
42
  cf_space_name = var.mgmt_space_name
@@ -44,7 +44,7 @@ module "mgmt_space" {
44
44
  }
45
45
 
46
46
  module "s3" {
47
- source = "github.com/gsa-tts/terraform-cloudgov//s3?ref=v2.1.0"
47
+ source = "github.com/gsa-tts/terraform-cloudgov//s3?ref=v2.3.0"
48
48
 
49
49
  cf_space_id = module.mgmt_space.space_id
50
50
  name = "<%= app_name %>-terraform-state"
@@ -134,7 +134,7 @@ locals {
134
134
  }
135
135
  resource "local_sensitive_file" "bucket_creds" {
136
136
  content = local.backend_config
137
- filename = "${path.module}/../secrets.backend.tfvars"
137
+ filename = "${path.module}/../.shadowenv.d/500_tf_backend_secrets.lisp"
138
138
  file_permission = "0600"
139
139
  }
140
140
 
@@ -150,10 +150,3 @@ resource "local_sensitive_file" "bot_secrets_file" {
150
150
  password = local.sa_cf_password
151
151
  })
152
152
  }
153
-
154
- output "mgmt_space_id" {
155
- value = module.mgmt_space.space_id
156
- }
157
- output "mgmt_org_id" {
158
- value = data.cloudfoundry_org.org.id
159
- }