diff --git a/doc/source/signing.rst b/doc/source/signing.rst new file mode 100644 index 0000000000..a0209ddf25 --- /dev/null +++ b/doc/source/signing.rst @@ -0,0 +1,87 @@ +:title: Signing System + +.. _signing: + +Signing System +############## + +This machine corresponds to the ``signing`` node label in job +configuration, holding an unencrypted copy of the OpenPGP signing +subkey for ``OpenStack Infra (Some Cycle) +`` used to create detached signatures for +release artifacts (tarballs, wheels, et cetera) and to sign and push +Git tags as part of our managed release automation. It only runs CI +jobs for tasks which require access to this key, using only vetted +tools and scripts reviewed by the Infra team. + + +At a Glance +=========== + +:Hosts: + * signing*.ci.openstack.org +:Puppet: + * :file:`modules/openstack_project/manifests/signing_node.pp` + + +Key Management Overview +======================= + +The signing server is a fairly typical long-lived job node, +distinguished primarily by having the signing subkey pair installed +by Puppet into the job runner account's home directory from binary +blobs in hiera. These blobs correspond to the +``~/.gnupg/pubring.gpg`` and ``~/.gnupg/secring.gpg`` files of a +freshly initialized gpg config after importing a minimal unencrypted +export on the management bastion of only the desired signing subkey +from the ``/root/signing.gunpg`` directory. + + +Storage +------- + +While the signing subkey is present unencrypted on this system, the +corresponding master key is kept symmetrically encrypted in the root +home directory of the Infra systems management bastion instead. At +the time of key creation a revocation certificate is also generated, +for which Infra root sysadmins are encouraged to retrieve and keep +local copies in case control over or access to the original master +key is lost. In the future, the master key and revocation +certificate may be distributed across our root team rather than kept +in one place (for example using Shamir's secret sharing scheme +similar to what `the Debian Project does for its archive keys +`). + + +Rotation +-------- + +The master key is rotated at the start of each development cycle, +signed by a majority of Infra root sysadmins before being put into +service, and has an expiration date set for shortly after the end of +the targeted development cycle. As each new key is created and +brought into rotation, an announcement should be signed by both the +old and new keys and sent to the +openstack-announce@lists.openstack.org mailing list. The new key +should also be signed by the old, and this signature pushed to the +public keyserver network. New key fingerprints are also submitted to +the openstack/releases repository, for publication on the +releases.openstack.org Web site. + + +Revocation +---------- + +Under normal circumstances, keys should be allowed to expire +gracefully. If the key is compromised but still accessible, a +revocation certificate can be generated and published to the key +network at that time. If access to the private key is lost +completely, the revocation certificate generated at key creation +time should be used as a last resort. + + +Management +========== + +As process is solidified, this section will be updated with specific +commands and examples. diff --git a/doc/source/systems.rst b/doc/source/systems.rst index 185e22e607..52c0e194a2 100644 --- a/doc/source/systems.rst +++ b/doc/source/systems.rst @@ -37,6 +37,7 @@ Major Systems translate refstack codesearch + signing .. NOTE(dhellmann): These projects were not listed above, or in any other toctree, which breaks the build. It's not clear why they were diff --git a/hiera/group/zuul-merger.yaml b/hiera/group/zuul-merger.yaml index 96d90978db..7c6849824c 100644 --- a/hiera/group/zuul-merger.yaml +++ b/hiera/group/zuul-merger.yaml @@ -42,6 +42,10 @@ zuul_nodes: host: 'release.slave.openstack.org' labels: 'release' + - name: 'signing01.ci.openstack.org' + host: 'signing01.ci.openstack.org' + labels: 'signing' + - name: 'wheel-mirror-centos-7-amd64.slave.openstack.org' host: 'wheel-mirror-centos-7-amd64.slave.openstack.org' labels: 'wheel-mirror-centos-7-amd64' diff --git a/manifests/site.pp b/manifests/site.pp index a004683ec2..b65cd3e08f 100644 --- a/manifests/site.pp +++ b/manifests/site.pp @@ -936,6 +936,16 @@ node 'release.slave.openstack.org' { } } +# Node-OS: trusty +node /^signing\d+\.ci\.openstack\.org$/ { + include openstack_project + class { 'openstack_project::signing_node': + jenkins_ssh_public_key => $openstack_project::jenkins_ssh_key, + pubring => hiera('pubring'), + secring => hiera('secring'), + } +} + # Node-OS: trusty node 'openstackid.org' { class { 'openstack_project::openstackid_prod': diff --git a/modules/openstack_project/files/puppetmaster/groups.txt b/modules/openstack_project/files/puppetmaster/groups.txt index b6e9c8d9df..5524ccd4b1 100644 --- a/modules/openstack_project/files/puppetmaster/groups.txt +++ b/modules/openstack_project/files/puppetmaster/groups.txt @@ -10,4 +10,5 @@ afsdb afsdb*.openstack.org afs afs*.*.openstack.org wheel-mirror *wheel-mirror-*.openstack.org afsadmin mirror-update.openstack.org:release.slave.openstack.org +signing signing*.ci.openstack.org disabled review-dev.openstack.org:ci-backup-rs-ord.openstack.org:ask-staging.openstack.org:db368fcd-e61a-4294-a5cb-851c16650f7a:wiki.openstack.org diff --git a/modules/openstack_project/files/puppetmaster/signing.conf b/modules/openstack_project/files/puppetmaster/signing.conf new file mode 100644 index 0000000000..436679d2f5 --- /dev/null +++ b/modules/openstack_project/files/puppetmaster/signing.conf @@ -0,0 +1,24 @@ +# A basic ~/.gnupg/gpg.conf using secure keyserver transport +# and some more verbose display options + +# Receive, send and search for keys in the SKS keyservers pool using +# HKPS (OpenPGP HTTP Keyserver Protocol via TLS/SSL). +keyserver hkps://hkps.pool.sks-keyservers.net + +# Set the path to the public certificate for the +# sks-keyservers.net CA used to verify connections to servers in +# the pool above. +keyserver-options ca-cert-file=/root/signing.gnupg/sks-keyservers.netCA.pem + +# Ignore keyserver URLs specified in retrieved/refreshed keys +# so they don't direct you to update from non-HKPS sources. +keyserver-options no-honor-keyserver-url + +# Display key IDs in a more accurate 16-digit hexidecimal format +# and add 0x at the beginning for clarity. +keyid-format 0xlong + +# Display the calculated validity of user IDs when listing keys or +# showing signatures. +list-options show-uid-validity +verify-options show-uid-validity diff --git a/modules/openstack_project/files/puppetmaster/sks-ca.pem b/modules/openstack_project/files/puppetmaster/sks-ca.pem new file mode 100644 index 0000000000..24a2ad2e8e --- /dev/null +++ b/modules/openstack_project/files/puppetmaster/sks-ca.pem @@ -0,0 +1,32 @@ +-----BEGIN CERTIFICATE----- +MIIFizCCA3OgAwIBAgIJAK9zyLTPn4CPMA0GCSqGSIb3DQEBBQUAMFwxCzAJBgNV +BAYTAk5PMQ0wCwYDVQQIDARPc2xvMR4wHAYDVQQKDBVza3Mta2V5c2VydmVycy5u +ZXQgQ0ExHjAcBgNVBAMMFXNrcy1rZXlzZXJ2ZXJzLm5ldCBDQTAeFw0xMjEwMDkw +MDMzMzdaFw0yMjEwMDcwMDMzMzdaMFwxCzAJBgNVBAYTAk5PMQ0wCwYDVQQIDARP +c2xvMR4wHAYDVQQKDBVza3Mta2V5c2VydmVycy5uZXQgQ0ExHjAcBgNVBAMMFXNr +cy1rZXlzZXJ2ZXJzLm5ldCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC +ggIBANdsWy4PXWNUCkS3L//nrd0GqN3dVwoBGZ6w94Tw2jPDPifegwxQozFXkG6I +6A4TK1CJLXPvfz0UP0aBYyPmTNadDinaB9T4jIwd4rnxl+59GiEmqkN3IfPsv5Jj +MkKUmJnvOT0DEVlEaO1UZIwx5WpfprB3mR81/qm4XkAgmYrmgnLXd/pJDAMk7y1F +45b5zWofiD5l677lplcIPRbFhpJ6kDTODXh/XEdtF71EAeaOdEGOvyGDmCO0GWqS +FDkMMPTlieLA/0rgFTcz4xwUYj/cD5e0ZBuSkYsYFAU3hd1cGfBue0cPZaQH2HYx +Qk4zXD8S3F4690fRhr+tki5gyG6JDR67aKp3BIGLqm7f45WkX1hYp+YXywmEziM4 +aSbGYhx8hoFGfq9UcfPEvp2aoc8u5sdqjDslhyUzM1v3m3ZGbhwEOnVjljY6JJLx +MxagxnZZSAY424ZZ3t71E/Mn27dm2w+xFRuoy8JEjv1d+BT3eChM5KaNwrj0IO/y +u8kFIgWYA1vZ/15qMT+tyJTfyrNVV/7Df7TNeWyNqjJ5rBmt0M6NpHG7CrUSkBy9 +p8JhimgjP5r0FlEkgg+lyD+V79H98gQfVgP3pbJICz0SpBQf2F/2tyS4rLm+49rP +fcOajiXEuyhpcmzgusAj/1FjrtlynH1r9mnNaX4e+rLWzvU5AgMBAAGjUDBOMB0G +A1UdDgQWBBTkwyoJFGfYTVISTpM8E+igjdq28zAfBgNVHSMEGDAWgBTkwyoJFGfY +TVISTpM8E+igjdq28zAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4ICAQAR +OXnYwu3g1ZjHyley3fZI5aLPsaE17cOImVTehC8DcIphm2HOMR/hYTTL+V0G4P+u +gH+6xeRLKSHMHZTtSBIa6GDL03434y9CBuwGvAFCMU2GV8w92/Z7apkAhdLToZA/ +X/iWP2jeaVJhxgEcH8uPrnSlqoPBcKC9PrgUzQYfSZJkLmB+3jEa3HKruy1abJP5 +gAdQvwvcPpvYRnIzUc9fZODsVmlHVFBCl2dlu/iHh2h4GmL4Da2rRkUMlbVTdioB +UYIvMycdOkpH5wJftzw7cpjsudGas0PARDXCFfGyKhwBRFY7Xp7lbjtU5Rz0Gc04 +lPrhDf0pFE98Aw4jJRpFeWMjpXUEaG1cq7D641RpgcMfPFvOHY47rvDTS7XJOaUT +BwRjmDt896s6vMDcaG/uXJbQjuzmmx3W2Idyh3s5SI0GTHb0IwMKYb4eBUIpQOnB +cE77VnCYqKvN1NVYAqhWjXbY7XasZvszCRcOG+W3FqNaHOK/n/0ueb0uijdLan+U +f4p1bjbAox8eAOQS/8a3bzkJzdyBNUKGx1BIK2IBL9bn/HravSDOiNRSnZ/R3l9G +ZauX0tu7IIDlRCILXSyeazu0aj/vdT3YFQXPcvt5Fkf5wiNTo53f72/jYEJd6qph +WrpoKqrwGwTpRUCMhYIUt65hsTxCiJJ5nKe39h46sg== +-----END CERTIFICATE----- diff --git a/modules/openstack_project/manifests/puppetmaster.pp b/modules/openstack_project/manifests/puppetmaster.pp index 824fc8250d..82c9a6a2fc 100644 --- a/modules/openstack_project/manifests/puppetmaster.pp +++ b/modules/openstack_project/manifests/puppetmaster.pp @@ -176,6 +176,36 @@ class openstack_project::puppetmaster ( ensure => absent, } + # For signing key management + package { 'gnupg': + ensure => present, + } + package { 'gnupg-curl': + ensure => present, + } + file { '/root/signing.gnupg': + ensure => directory, + owner => 'root', + group => 'root', + mode => '0700', + } + file { '/root/signing.gnupg/gpg.conf': + ensure => present, + owner => 'root', + group => 'root', + mode => '0400', + source => 'puppet:///modules/openstack_project/puppetmaster/signing.conf', + require => File['/root/signing.gnupg'], + } + file { '/root/signing.gnupg/sks-keyservers.netCA.pem': + ensure => present, + owner => 'root', + group => 'root', + mode => '0400', + source => 'puppet:///modules/openstack_project/puppetmaster/sks-ca.pem', + require => File['/root/signing.gnupg'], + } + # Enable puppetdb if $puppetdb { diff --git a/modules/openstack_project/manifests/signing_node.pp b/modules/openstack_project/manifests/signing_node.pp new file mode 100644 index 0000000000..e723114847 --- /dev/null +++ b/modules/openstack_project/manifests/signing_node.pp @@ -0,0 +1,60 @@ +# Copyright 2016 OpenStack Foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Class to install dependencies for uploading releases to pypi, maven and +# similar external repositories +# +class openstack_project::signing_node ( + $jenkins_ssh_public_key, + $pubring, + $secring, + $project_config_repo = 'https://git.openstack.org/openstack-infra/project-config', +) { + class { 'openstack_project::slave': + thin => true, + ssh_key => $jenkins_ssh_public_key, + project_config_repo => $project_config_repo, + } + + package { 'gnupg': + ensure => present, + } + + file { '/home/jenkins/.gnupg': + ensure => directory, + owner => 'jenkins', + group => 'jenkins', + mode => '0700', + require => File['/home/jenkins'], + } + + file { '/home/jenkins/.gnupg/pubring.gpg': + ensure => present, + owner => 'jenkins', + group => 'jenkins', + mode => '0400', + content => $pubring, + require => File['/home/jenkins/.gnupg'], + } + + file { '/home/jenkins/.gnupg/secring.gpg': + ensure => present, + owner => 'jenkins', + group => 'jenkins', + mode => '0400', + content => $secring, + require => File['/home/jenkins/.gnupg'], + } + +}