diff options
author | Kamil Trzciński <ayufan@ayufan.eu> | 2019-01-04 10:34:35 +0000 |
---|---|---|
committer | Kamil Trzciński <ayufan@ayufan.eu> | 2019-01-04 10:34:35 +0000 |
commit | 43687c62607075ee201b8ea1e16ac6e6563b45be (patch) | |
tree | 77ebb5da957717d4447395b1f1b85eacaf9614b2 | |
parent | 24985807dc9e642f1ac2ca6b6d24f086f8eb4282 (diff) | |
parent | 82a5cf0aad4cf0c67067cf03e34f539fe72ded76 (diff) | |
download | gitlab-ce-43687c62607075ee201b8ea1e16ac6e6563b45be.tar.gz |
Merge branch '49056-configure-auto-devops-deployed-applications-with-secrets-that-aren-t-committed-to-the-repo' into 'master'
Configure Auto DevOps deployed applications with secrets from prefixed CI variables
See merge request gitlab-org/gitlab-ce!23719
6 files changed, 141 insertions, 43 deletions
diff --git a/app/views/ci/variables/_content.html.haml b/app/views/ci/variables/_content.html.haml index fa82611d9c1..90c59bec975 100644 --- a/app/views/ci/variables/_content.html.haml +++ b/app/views/ci/variables/_content.html.haml @@ -1 +1,3 @@ = _('Environment variables are applied to environments via the runner. They can be protected by only exposing them to protected branches or tags. You can use environment variables for passwords, secret keys, or whatever you want.') += _('You may also add variables that are made available to the running application by prepending the variable key with <code>K8S_SECRET_</code>.').html_safe += link_to _('More information'), help_page_path('ci/variables/README', anchor: 'variables') diff --git a/changelogs/unreleased/49056-configure-auto-devops-deployed-applications-with-secrets-that-aren-t-committed-to-the-repo.yml b/changelogs/unreleased/49056-configure-auto-devops-deployed-applications-with-secrets-that-aren-t-committed-to-the-repo.yml new file mode 100644 index 00000000000..65efa85176b --- /dev/null +++ b/changelogs/unreleased/49056-configure-auto-devops-deployed-applications-with-secrets-that-aren-t-committed-to-the-repo.yml @@ -0,0 +1,5 @@ +--- +title: Configure Auto DevOps deployed applications with secrets from prefixed CI variables +merge_request: 23719 +author: +type: added diff --git a/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml b/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml index 8f6cf8d2d03..b5350f56f9c 100644 --- a/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml +++ b/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml @@ -596,10 +596,55 @@ rollout 100%: fi } + # Extracts variables prefixed with K8S_SECRET_ + # and creates a Kubernetes secret. + # + # e.g. If we have the following environment variables: + # K8S_SECRET_A=value1 + # K8S_SECRET_B=multi\ word\ value + # + # Then we will create a secret with the following key-value pairs: + # data: + # A: dmFsdWUxCg== + # B: bXVsdGkgd29yZCB2YWx1ZQo= + function create_application_secret() { + track="${1-stable}" + export APPLICATION_SECRET_NAME=$(application_secret_name "$track") + + bash -c ' + function k8s_prefixed_variables() { + env | sed -n "s/^K8S_SECRET_\(.*\)$/\1/p" + } + + kubectl create secret \ + -n "$KUBE_NAMESPACE" generic "$APPLICATION_SECRET_NAME" \ + --from-env-file <(k8s_prefixed_variables) -o yaml --dry-run | + kubectl replace -n "$KUBE_NAMESPACE" --force -f - + ' + } + + function deploy_name() { + name="$CI_ENVIRONMENT_SLUG" + track="${1-stable}" + + if [[ "$track" != "stable" ]]; then + name="$name-$track" + fi + + echo $name + } + + function application_secret_name() { + track="${1-stable}" + name=$(deploy_name "$track") + + echo "${name}-secret" + } + function deploy() { track="${1-stable}" percentage="${2:-100}" - name="$CI_ENVIRONMENT_SLUG" + name=$(deploy_name "$track") replicas="1" service_enabled="true" @@ -608,7 +653,6 @@ rollout 100%: # if track is different than stable, # re-use all attached resources if [[ "$track" != "stable" ]]; then - name="$name-$track" service_enabled="false" postgres_enabled="false" fi @@ -621,6 +665,8 @@ rollout 100%: secret_name='' fi + create_application_secret "$track" + if [[ -n "$DB_INITIALIZE" && -z "$(helm ls -q "^$name$")" ]]; then echo "Deploying first release with database initialization..." helm upgrade --install \ @@ -633,6 +679,7 @@ rollout 100%: --set image.secrets[0].name="$secret_name" \ --set application.track="$track" \ --set application.database_url="$DATABASE_URL" \ + --set application.secretName="$APPLICATION_SECRET_NAME" \ --set service.url="$CI_ENVIRONMENT_URL" \ --set replicaCount="$replicas" \ --set postgresql.enabled="$postgres_enabled" \ @@ -665,6 +712,7 @@ rollout 100%: --set image.secrets[0].name="$secret_name" \ --set application.track="$track" \ --set application.database_url="$DATABASE_URL" \ + --set application.secretName="$APPLICATION_SECRET_NAME" \ --set service.url="$CI_ENVIRONMENT_URL" \ --set replicaCount="$replicas" \ --set postgresql.enabled="$postgres_enabled" \ @@ -684,11 +732,7 @@ rollout 100%: function scale() { track="${1-stable}" percentage="${2-100}" - name="$CI_ENVIRONMENT_SLUG" - - if [[ "$track" != "stable" ]]; then - name="$name-$track" - fi + name=$(deploy_name "$track") replicas=$(get_replicas "$track" "$percentage") @@ -882,15 +926,14 @@ rollout 100%: function delete() { track="${1-stable}" - name="$CI_ENVIRONMENT_SLUG" - - if [[ "$track" != "stable" ]]; then - name="$name-$track" - fi + name=$(deploy_name "$track") if [[ -n "$(helm ls -q "^$name$")" ]]; then helm delete --purge "$name" fi + + secret_name=$(application_secret_name "$track") + kubectl delete secret --ignore-not-found -n "$KUBE_NAMESPACE" "$secret_name" } before_script: diff --git a/locale/gitlab.pot b/locale/gitlab.pot index ddfd5599883..10a3a70b32a 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -7719,6 +7719,9 @@ msgstr "" msgid "You have reached your project limit" msgstr "" +msgid "You may also add variables that are made available to the running application by prepending the variable key with <code>K8S_SECRET_</code>." +msgstr "" + msgid "You must accept our Terms of Service and privacy policy in order to register an account" msgstr "" diff --git a/qa/qa/fixtures/auto_devops_rack/config.ru b/qa/qa/fixtures/auto_devops_rack/config.ru index bde8e15488a..e990662145a 100644 --- a/qa/qa/fixtures/auto_devops_rack/config.ru +++ b/qa/qa/fixtures/auto_devops_rack/config.ru @@ -1 +1 @@ -run lambda { |env| [200, { 'Content-Type' => 'text/plain' }, StringIO.new("Hello World!\n")] } +run lambda { |env| [200, { 'Content-Type' => 'text/plain' }, StringIO.new("Hello World! #{ENV['OPTIONAL_MESSAGE']}\n")] } diff --git a/qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb b/qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb index b0c277a48c3..6cd5c06a088 100644 --- a/qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb +++ b/qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb @@ -5,60 +5,73 @@ require 'pathname' module QA context 'Configure', :orchestrated, :kubernetes do describe 'Auto DevOps support' do - after do - @cluster&.remove! + def login + Runtime::Browser.visit(:gitlab, Page::Main::Login) + Page::Main::Login.act { sign_in_using_credentials } end - [true, false].each do |rbac| - context "when rbac is #{rbac ? 'enabled' : 'disabled'}" do - it 'user creates a new project and runs auto devops' do - Runtime::Browser.visit(:gitlab, Page::Main::Login) - Page::Main::Login.act { sign_in_using_credentials } + before(:all) do + login - project = Resource::Project.fabricate! do |p| - p.name = Runtime::Env.auto_devops_project_name || 'project-with-autodevops' - p.description = 'Project with Auto Devops' - end + @project = Resource::Project.fabricate! do |p| + p.name = Runtime::Env.auto_devops_project_name || 'project-with-autodevops' + p.description = 'Project with Auto Devops' + end - # Disable code_quality check in Auto DevOps pipeline as it takes - # too long and times out the test - Resource::CiVariable.fabricate! do |resource| - resource.project = project - resource.key = 'CODE_QUALITY_DISABLED' - resource.value = '1' - end + # Disable code_quality check in Auto DevOps pipeline as it takes + # too long and times out the test + Resource::CiVariable.fabricate! do |resource| + resource.project = @project + resource.key = 'CODE_QUALITY_DISABLED' + resource.value = '1' + end - # Create Auto Devops compatible repo - Resource::Repository::ProjectPush.fabricate! do |push| - push.project = project - push.directory = Pathname - .new(__dir__) - .join('../../../../../fixtures/auto_devops_rack') - push.commit_message = 'Create Auto DevOps compatible rack application' - end + # Create Auto Devops compatible repo + Resource::Repository::ProjectPush.fabricate! do |push| + push.project = @project + push.directory = Pathname + .new(__dir__) + .join('../../../../../fixtures/auto_devops_rack') + push.commit_message = 'Create Auto DevOps compatible rack application' + end - Page::Project::Show.act { wait_for_push } + Page::Project::Show.act { wait_for_push } + end + [true, false].each do |rbac| + context "when rbac is #{rbac ? 'enabled' : 'disabled'}" do + before(:all) do # Create and connect K8s cluster @cluster = Service::KubernetesCluster.new(rbac: rbac).create! kubernetes_cluster = Resource::KubernetesCluster.fabricate! do |cluster| - cluster.project = project + cluster.project = @project cluster.cluster = @cluster cluster.install_helm_tiller = true cluster.install_ingress = true cluster.install_prometheus = true cluster.install_runner = true end + kubernetes_cluster.populate(:ingress_ip) - project.visit! + @project.visit! Page::Project::Menu.act { click_ci_cd_settings } Page::Project::Settings::CICD.perform do |p| p.enable_auto_devops_with_domain( "#{kubernetes_cluster.ingress_ip}.nip.io") end + end - project.visit! + after(:all) do + @cluster&.remove! + end + + before do + login + end + + it 'runs auto devops' do + @project.visit! Page::Project::Menu.act { click_ci_cd_pipelines } Page::Project::Pipeline::Index.act { go_to_latest_pipeline } @@ -78,6 +91,38 @@ module QA end end end + + it 'user sets application secret variable and Auto DevOps passes it to container' do + # Set an application secret CI variable (prefixed with K8S_SECRET_) + Resource::CiVariable.fabricate! do |resource| + resource.project = @project + resource.key = 'K8S_SECRET_OPTIONAL_MESSAGE' + resource.value = 'You can see this application secret' + end + + @project.visit! + Page::Project::Menu.act { click_ci_cd_pipelines } + Page::Project::Pipeline::Index.act { go_to_latest_pipeline } + + Page::Project::Pipeline::Show.perform do |pipeline| + expect(pipeline).to have_build('build', status: :success, wait: 600) + expect(pipeline).to have_build('test', status: :success, wait: 600) + expect(pipeline).to have_build('production', status: :success, wait: 1200) + end + + Page::Project::Menu.act { click_operations_environments } + + Page::Project::Operations::Environments::Index.perform do |index| + index.go_to_environment('production') + end + + Page::Project::Operations::Environments::Show.perform do |show| + show.view_deployment do + expect(page).to have_content('Hello World!') + expect(page).to have_content('You can see this application secret') + end + end + end end end end |