OSDN Git Service

adds the ['concourse-ci']['docker-compose']['web_oauth_client_(id|secret)_vault_item... concourse-ci-0.1.6
authorwhitestar <whitestar@gaea.test>
Sun, 26 Feb 2017 09:27:26 +0000 (18:27 +0900)
committerwhitestar <whitestar@gaea.test>
Sun, 26 Feb 2017 09:27:26 +0000 (18:27 +0900)
cookbooks/concourse-ci/CHANGELOG.md
cookbooks/concourse-ci/README.md
cookbooks/concourse-ci/attributes/default.rb
cookbooks/concourse-ci/metadata.rb
cookbooks/concourse-ci/recipes/docker-compose.rb
cookbooks/concourse-ci/templates/default/opt/docker-compose/app/concourse/.env
cookbooks/concourse-ci/templates/default/opt/docker-compose/app/concourse/bin/concourse_import_ca [new file with mode: 0644]
cookbooks/concourse-ci/templates/default/opt/docker-compose/app/concourse/bin/concourse_up [new file with mode: 0644]

index d854bb1..be536ab 100644 (file)
@@ -1,6 +1,11 @@
 concourse-ci CHANGELOG
 ======================
 
+0.1.6
+-----
+- adds CA certificates import feature.
+- adds the `['concourse-ci']['docker-compose']['web_oauth_client_(id|secret)_vault_item']` attributes.
+
 0.1.5
 -----
 - adds the `concourse-ci::fly` recipe.
index 27ab754..a23ca69 100644 (file)
@@ -17,6 +17,7 @@ This cookbook sets up a Concourse CI service by Docker Compose.
         - [concourse-ci::docker-compose](#concourse-cidocker-compose)
     - [Role Examples](#role-examples)
     - [SSL server keys and certificates management by ssl_cert cookbook](#ssl-server-keys-and-certificates-management-by-ssl_cert-cookbook)
+    - [OAuth client ID and secret management by Chef Vault](#oauth-client-id-and-secret-management-by-chef-vault)
 - [License and Authors](#license-and-authors)
 
 ## Requirements
@@ -40,6 +41,10 @@ This cookbook sets up a Concourse CI service by Docker Compose.
 |`['concourse-ci']['fly']['release_checksum']`|String||`nil`|
 |`['concourse-ci']['fly']['auto_upgrade']`|Boolean||`false`|
 |`['concourse-ci']['fly']['install_path']`|String||`'/usr/local/bin/fly'`|
+|`['concourse-ci']['with_ssl_cert_cookbook']`|Boolean|See `attributes/default.rb`|`false`|
+|`['concourse-ci']['ssl_cert']['ca_names']`|Array|Internal CA names that are imported by the ssl_cert cookbook.|`[]`|
+|`['concourse-ci']['ssl_cert']['common_name']`|String|Server common name for TLS|`node['fqdn']`|
+|`['concourse-ci']['docker-compose']['import_ca']`|Boolean|whether import internal CA certificates or not.|`false`|
 |`['concourse-ci']['docker-compose']['app_dir']`|String||`"#{node['docker-grid']['compose']['app_dir']}/concourse"`|
 |`['concourse-ci']['docker-compose']['pgdata_dir']`|String|Path string or nil (unset).|`"#{node['concourse-ci']['docker-compose']['app_dir']}/database"`|
 |`['concourse-ci']['docker-compose']['web_keys_dir']`|String|Path string.|`"#{node['concourse-ci']['docker-compose']['app_dir']}/keys/web"`|
@@ -49,6 +54,8 @@ This cookbook sets up a Concourse CI service by Docker Compose.
 |`['concourse-ci']['docker-compose']['db_password_vault_item']`|Hash|See `attributes/default.rb`|`{}`|
 |`['concourse-ci']['docker-compose']['web_password_reset']`|String|Only available if the password is automatically generated by Chef.|`false`|
 |`['concourse-ci']['docker-compose']['web_password_vault_item']`|Hash|See `attributes/default.rb`|`{}`|
+|`['concourse-ci']['docker-compose']['web_oauth_client_id_vault_item']`|Hash|See `attributes/default.rb`|`{}`|
+|`['concourse-ci']['docker-compose']['web_oauth_client_secret_vault_item']`|Hash|See `attributes/default.rb`|`{}`|
 |`['concourse-ci']['docker-compose']['ssh_keys_reset']`|String|Resets all SSH keys forcely.|`false`|
 |`['concourse-ci']['docker-compose']['config_format_version']`|String|Read only. `docker-compose.yml` format version. Only version 1 is supported now.|`'1'`|
 |`['concourse-ci']['docker-compose']['config']`|Hash|`docker-compose.yml` configurations.|See `attributes/default.rb`|
@@ -178,6 +185,82 @@ override_attributes(
 )
 ```
 
+- `roles/concourse-with-oauth.rb`
+
+```ruby
+name 'concourse-with-oauth'
+description 'Concourse with OAuth'
+
+run_list(
+  'recipe[ssl_cert::ca_certs]',
+  'recipe[ssl_cert::server_key_pairs]',
+  'role[docker]',
+  'recipe[concourse-ci::docker-compose]',
+)
+
+image = 'concourse/concourse:2.7.0'
+port = '18443'
+ca_name = 'grid_ca'
+cn = 'concourse.io.example.com'
+gitlab_cn = 'gitlab.io.example.com'
+
+override_attributes(
+  'ssl_cert' => {
+    'ca_names' => [
+      ca_name,
+    ],
+    'common_names' => [
+      cn,
+    ],
+  },
+  'concourse-ci' => {
+    'with_ssl_cert_cookbook' => true,
+    'ssl_cert' => {
+      'ca_names' => [
+        ca_name,
+      ],
+      'common_name' => cn,
+    },
+    'docker-compose' => {
+      'import_ca' => true,
+      'web_oauth_client_id_vault_item' => {
+        'vault' => 'concourse',
+        'name' => 'web_oauth_client_id',
+        'env_context' => false,
+        'key' => 'cid',
+      },
+      'web_oauth_client_secret_vault_item' => {
+        'vault' => 'concourse',
+        'name' => 'web_oauth_client_secret',
+        'env_context' => false,
+        'key' => 'secret',
+      },
+      'config' => {
+        # Version 1 docker-compose format
+        'concourse-web' => {
+          'ports' => [
+            #'4080:8080',
+            "#{port}:8443",
+          ],
+          'environment' => {
+            'CONCOURSE_TLS_BIND_PORT' => '8443',
+            'CONCOURSE_EXTERNAL_URL' => "https://#{cn}:#{port}",
+            # OAuth for the default `main`` team
+            'CONCOURSE_GENERIC_OAUTH_DISPLAY_NAME' => 'GitLab',
+            # The following 2 variables are set automatically,
+            # if the ['concourse-ci']['docker-compose']['web_oauth_client_(id|secret)_vault_item'] attributes are specified.
+            #'CONCOURSE_GENERIC_OAUTH_CLIENT_ID' => '${CONCOURSE_GENERIC_OAUTH_CLIENT_ID}',
+            #'CONCOURSE_GENERIC_OAUTH_CLIENT_SECRET' => '${CONCOURSE_GENERIC_OAUTH_CLIENT_SECRET}',
+            'CONCOURSE_GENERIC_OAUTH_AUTH_URL' => "https://#{gitlab_cn}/oauth/authorize",
+            'CONCOURSE_GENERIC_OAUTH_TOKEN_URL' => "https://#{gitlab_cn}/oauth/token",
+          },
+        },
+      },
+    },
+  },
+)
+```
+
 ### SSL server keys and certificates management by ssl_cert cookbook
 
 - create vault items.
@@ -186,12 +269,14 @@ override_attributes(
 $ ruby -rjson -e 'puts JSON.generate({"private" => File.read("concourse_io_example_com.prod.key")})' \
 > > ~/tmp/concourse_io_example_com.prod.key.json
 
-$ knife vault create ssl_server_keys concourse.io.example.com.prod \
-> --json ~/tmp/concourse_io_example_com.prod.key.json
-
 $ ruby -rjson -e 'puts JSON.generate({"public" => File.read("concourse_io_example_com.prod.crt")})' \
 > > ~/tmp/concourse_io_example_com.prod.crt.json
 
+$ cd $CHEF_REPO_PATH
+
+$ knife vault create ssl_server_keys concourse.io.example.com.prod \
+> --json ~/tmp/concourse_io_example_com.prod.key.json
+
 $ knife vault create ssl_server_certs concourse.io.example.com.prod \
 > --json ~/tmp/concourse_io_example_com.prod.crt.json
 ```
@@ -227,6 +312,52 @@ override_attributes(
 )
 ```
 
+### OAuth client ID and secret management by Chef Vault
+
+- create vault items.
+
+```text
+$ cat ~/tmp/concourse_oauth_client_id.json
+{"cid":"***************************************************************"}
+$ cat ~/tmp/concourse_oauth_client_secret.json
+{"secret":"***************************************************************"}
+
+$ knife vault create concourse web_oauth_client_id --json ~/tmp/concourse_oauth_client_id.json
+$ knife vault create concourse web_oauth_client_secret --json ~/tmp/concourse_oauth_client_secret.json
+```
+
+- grant reference permission to the Concourse host
+
+```text
+$ knife vault update concourse web_oauth_client_id -S 'name:concourse-host.example.com'
+$ knife vault update concourse web_oauth_client_secret -S 'name:concourse-host.example.com'
+```
+
+- modify attributes
+
+```ruby
+override_attributes(
+  'concourse-ci' => {
+    # ...
+    'docker-compose' => {
+      'web_oauth_client_id_vault_item' => {
+        'vault' => 'concourse',
+        'name' => 'web_oauth_client_id',
+        'env_context' => false,
+        'key' => 'cid',
+      },
+      'web_oauth_client_secret_vault_item' => {
+        'vault' => 'concourse',
+        'name' => 'web_oauth_client_secret',
+        'env_context' => false,
+        'key' => 'secret',
+      },
+      # ...
+    },
+  },
+)
+```
+
 ## License and Authors
 
 - Author:: whitestar at osdn.jp
index 0a7e32e..bfdf9e2 100644 (file)
@@ -27,7 +27,9 @@ default['concourse-ci']['with_ssl_cert_cookbook'] = false
 # If ['concourse-ci']['with_ssl_cert_cookbook'] is true,
 # node['concourse-ci']['docker-compose']['config']
 # are overridden by the following 'common_name' attributes.
+default['concourse-ci']['ssl_cert']['ca_names'] = []
 default['concourse-ci']['ssl_cert']['common_name'] = node['fqdn']
+default['concourse-ci']['docker-compose']['import_ca'] = false
 default['concourse-ci']['docker-compose']['app_dir'] = "#{node['docker-grid']['compose']['app_dir']}/concourse"
 default['concourse-ci']['docker-compose']['pgdata_dir'] = "#{node['concourse-ci']['docker-compose']['app_dir']}/database"
 default['concourse-ci']['docker-compose']['web_keys_dir'] = "#{node['concourse-ci']['docker-compose']['app_dir']}/keys/web"
@@ -58,6 +60,30 @@ default['concourse-ci']['docker-compose']['web_password_vault_item'] = {
   #'key' => 'hash/path/to/password',  # real hash path: "/#{node.chef_environment}/hash/path/to/password"
 =end
 }
+default['concourse-ci']['docker-compose']['web_oauth_client_id_vault_item'] = {
+=begin
+  'vault' => 'concourse',
+  'name' => 'web_oauth_client_id',
+  # single cid or nested hash cid path delimited by slash
+  'env_context' => false,
+  'key' => 'cid',  # real hash path: "/cid", Note: do not use `id`, which is preserved by Chef Vault.
+  # or nested hash id path delimited by slash
+  #'env_context' => true,
+  #'key' => 'hash/path/to/cid',  # real hash path: "/#{node.chef_environment}/hash/path/to/cid"
+=end
+}
+default['concourse-ci']['docker-compose']['web_oauth_client_secret_vault_item'] = {
+=begin
+  'vault' => 'concourse',
+  'name' => 'web_oauth_client_secret',
+  # single secret or nested hash secret path delimited by slash
+  'env_context' => false,
+  'key' => 'secret',  # real hash path: "/secret"
+  # or nested hash secret path delimited by slash
+  #'env_context' => true,
+  #'key' => 'hash/path/to/secret',  # real hash path: "/#{node.chef_environment}/hash/path/to/secret"
+=end
+}
 default['concourse-ci']['docker-compose']['ssh_keys_reset'] = false
 
 # TODO: support version 2 format, and use `default` instead of `force_override`
@@ -97,6 +123,14 @@ version_1_config = {
       'CONCOURSE_BASIC_AUTH_USERNAME' => 'concourse',
       # Note: You should use the `['concourse-ci']['docker-compose']['web_password_vault_item']` attribute.
       'CONCOURSE_BASIC_AUTH_PASSWORD' => nil,
+      # OAuth for the default `main`` team
+      #'CONCOURSE_GENERIC_OAUTH_DISPLAY_NAME' => 'GitLab',
+      # The following 2 variables are set automatically,
+      # if the ['concourse-ci']['docker-compose']['web_oauth_client_(id|secret)_vault_item'] attributes are specified.
+      #'CONCOURSE_GENERIC_OAUTH_CLIENT_ID' => '${CONCOURSE_GENERIC_OAUTH_CLIENT_ID}',
+      #'CONCOURSE_GENERIC_OAUTH_CLIENT_SECRET' => '${CONCOURSE_GENERIC_OAUTH_CLIENT_SECRET}',
+      #'CONCOURSE_GENERIC_OAUTH_AUTH_URL' => 'https://gitlab.io.example.com/oauth/authorize',
+      #'CONCOURSE_GENERIC_OAUTH_TOKEN_URL' => 'https://gitlab.io.example.com/oauth/token',
       # If you sepecify no value, Chef will sets "http://#{node['ipaddress']}:8080".
       'CONCOURSE_EXTERNAL_URL' => nil,
       # `${POSTGRES_PASSWORD}` is a placeholder of password string.
index 22190c6..382fbfe 100644 (file)
@@ -5,7 +5,7 @@ maintainer_email ''
 license          'Apache 2.0'
 description      'Installs/Configures Concourse CI by Docker Compose'
 long_description IO.read(File.join(File.dirname(__FILE__), 'README.md'))
-version          '0.1.5'
+version          '0.1.6'
 source_url       'http://scm.osdn.jp/gitroot/metasearch/grid-chef-repo.git'
 issues_url       'https://osdn.jp/projects/metasearch/ticket'
 
index 23aeea4..d49697c 100644 (file)
@@ -27,12 +27,14 @@ include_recipe 'platform_utils::kernel_user_namespace'
 include_recipe 'docker-grid::compose'
 
 app_dir = node['concourse-ci']['docker-compose']['app_dir']
+bin_dir = "#{app_dir}/bin"
 pgdata_dir = node['concourse-ci']['docker-compose']['pgdata_dir']
 web_keys_dir = node['concourse-ci']['docker-compose']['web_keys_dir']
 worker_keys_dir = node['concourse-ci']['docker-compose']['worker_keys_dir']
 
 [
   app_dir,
+  bin_dir,
   web_keys_dir,
   worker_keys_dir,
 ].each {|dir|
@@ -180,6 +182,20 @@ end
 # prevent Chef from logging password attribute value. (=> template variables)
 web_envs['CONCOURSE_BASIC_AUTH_PASSWORD'] = '${CONCOURSE_BASIC_AUTH_PASSWORD}'
 
+oauth_client_id = nil
+oauth_client_id_vault_item = node['concourse-ci']['docker-compose']['web_oauth_client_id_vault_item']
+unless oauth_client_id_vault_item.empty?
+  oauth_client_id = get_vault_item_value(oauth_client_id_vault_item)
+  web_envs['CONCOURSE_GENERIC_OAUTH_CLIENT_ID'] = '${CONCOURSE_GENERIC_OAUTH_CLIENT_ID}'
+end
+
+oauth_client_secret = nil
+oauth_client_secret_vault_item = node['concourse-ci']['docker-compose']['web_oauth_client_secret_vault_item']
+unless oauth_client_secret_vault_item.empty?
+  oauth_client_secret = get_vault_item_value(oauth_client_secret_vault_item)
+  web_envs['CONCOURSE_GENERIC_OAUTH_CLIENT_SECRET'] = '${CONCOURSE_GENERIC_OAUTH_CLIENT_SECRET}'
+end
+
 external_url = web_envs_org['CONCOURSE_EXTERNAL_URL']
 web_envs['CONCOURSE_EXTERNAL_URL'] = "http://#{node['ipaddress']}:8080" if external_url.nil?
 
@@ -188,6 +204,30 @@ data_source = web_envs_org['CONCOURSE_POSTGRES_DATA_SOURCE']
 data_source = data_source.gsub(/<POSTGRES_PASSWORD>/, '${POSTGRES_PASSWORD}')
 web_envs['CONCOURSE_POSTGRES_DATA_SOURCE'] = data_source
 
+if node['concourse-ci']['docker-compose']['import_ca']
+  ::Chef::Recipe.send(:include, SSLCert::Helper)
+  node['concourse-ci']['ssl_cert']['ca_names'].each {|ca_name|
+    web_vols.push("#{ca_cert_path(ca_name)}:/usr/share/ca-certificates/#{ca_name}.crt:ro")
+  }
+
+  template "#{bin_dir}/concourse_import_ca" do
+    source 'opt/docker-compose/app/concourse/bin/concourse_import_ca'
+    owner 'root'
+    group 'root'
+    mode '0755'
+    action :create
+  end
+  web_vols.push("#{bin_dir}/concourse_import_ca:/usr/local/bin/concourse_import_ca:ro")
+end
+
+template "#{bin_dir}/concourse_up" do
+  source 'opt/docker-compose/app/concourse/bin/concourse_up'
+  owner 'root'
+  group 'root'
+  mode '0755'
+  action :create
+end
+
 if node['concourse-ci']['with_ssl_cert_cookbook']
   ::Chef::Recipe.send(:include, SSLCert::Helper)
   cn = node['concourse-ci']['ssl_cert']['common_name']
@@ -219,7 +259,9 @@ template env_file do
   variables(
     # secrets
     db_passwd: db_passwd,
-    basic_auth_passwd: basic_auth_passwd
+    basic_auth_passwd: basic_auth_passwd,
+    oauth_client_id: oauth_client_id,
+    oauth_client_secret: oauth_client_secret
   )
 end
 
@@ -235,7 +277,7 @@ Note: You must execute the following command manually.
   See #{doc_url}
   - Start:
     $ cd #{app_dir}
-    $ sudo docker-compose up -d
+    $ ./bin/concourse_up
   - Stop
     $ sudo docker-compose down
 EOM
index 0244fff..9284402 100644 (file)
@@ -5,3 +5,9 @@
 -%>
 POSTGRES_PASSWORD=<%= @db_passwd %>
 CONCOURSE_BASIC_AUTH_PASSWORD=<%= @basic_auth_passwd %>
+<% unless @oauth_client_id.nil? %>
+CONCOURSE_GENERIC_OAUTH_CLIENT_ID=<%= @oauth_client_id %>
+<% end %>
+<% unless @oauth_client_secret.nil? %>
+CONCOURSE_GENERIC_OAUTH_CLIENT_SECRET=<%= @oauth_client_secret %>
+<% end %>
diff --git a/cookbooks/concourse-ci/templates/default/opt/docker-compose/app/concourse/bin/concourse_import_ca b/cookbooks/concourse-ci/templates/default/opt/docker-compose/app/concourse/bin/concourse_import_ca
new file mode 100644 (file)
index 0000000..6466110
--- /dev/null
@@ -0,0 +1,12 @@
+#!/bin/sh\r
+\r
+<%\r
+node['concourse-ci']['ssl_cert']['ca_names'].each {|ca_name|\r
+-%>\r
+if ! cat /etc/ca-certificates.conf | grep <%= ca_name %>; then\r
+  echo <%= ca_name %>.crt >> /etc/ca-certificates.conf\r
+fi\r
+<%\r
+}\r
+-%>\r
+update-ca-certificates\r
diff --git a/cookbooks/concourse-ci/templates/default/opt/docker-compose/app/concourse/bin/concourse_up b/cookbooks/concourse-ci/templates/default/opt/docker-compose/app/concourse/bin/concourse_up
new file mode 100644 (file)
index 0000000..d09bb3e
--- /dev/null
@@ -0,0 +1,7 @@
+#!/bin/sh\r
+\r
+cd <%= node['concourse-ci']['docker-compose']['app_dir']  %>\r
+sudo docker-compose up -d\r
+<% if node['concourse-ci']['docker-compose']['import_ca'] %>\r
+sudo docker exec $(sudo docker ps | grep "concourse_concourse-web" | awk '{print $1}') concourse_import_ca\r
+<% end %>\r