20after4 has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/289236

Change subject: WIP: keyholder key cleanup
......................................................................

WIP: keyholder key cleanup

Bug: T132747

Change-Id: Id298a3e0f12e31afd7ea83970e192330ffbd4243
---
M hieradata/common/scap/server.yaml
M hieradata/labs/deployment-prep/common.yaml
M modules/eventlogging/manifests/deployment/target.pp
M modules/keyholder/files/keyholder
M modules/keyholder/files/ssh-agent-proxy
M modules/keyholder/manifests/agent.pp
D modules/keyholder/manifests/private_key.pp
D modules/phabricator/manifests/deployment/target.pp
M modules/phabricator/manifests/init.pp
M modules/role/manifests/deployment/mediawiki.pp
M modules/role/manifests/snapshot/deployment.pp
M modules/scap/manifests/target.pp
M modules/service/manifests/node.pp
M modules/zotero/manifests/init.pp
14 files changed, 103 insertions(+), 157 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/operations/puppet 
refs/changes/36/289236/1

diff --git a/hieradata/common/scap/server.yaml 
b/hieradata/common/scap/server.yaml
index 4568ed2..cf17508 100644
--- a/hieradata/common/scap/server.yaml
+++ b/hieradata/common/scap/server.yaml
@@ -12,24 +12,18 @@
 
   phabricator:
     trusted_group: deploy-phabricator
-    key_fingerprint: 39:b3:2c:a7:b2:80:65:ff:0c:97:e1:22:88:6c:59:10
-    key_secret: phabricator/phab_deploy_private_key
 
   eventlogging:
     trusted_group: eventlogging-admins
-    key_fingerprint: b6:4e:1a:1b:4b:70:ef:91:31:cd:a3:18:9a:ca:41:44
 
   deploy-service:
     trusted_group:
       - deploy-service
       - aqs-admins
-    key_fingerprint: 6d:54:92:8b:39:10:f5:9b:84:40:36:ef:3c:9a:6d:d8
-    key_file: servicedeploy_rsa
 
   dumpsdeploy:
     trusted_group: ops
-    key_fingerprint: 86:c9:17:ab:b7:00:79:b5:8a:c5:b5:ee:29:24:c9:2f
-
+    key_name: dumps
 
 # scap::source declarations.  These are created
 # by the scap::server class.  Each source listed here
@@ -61,4 +55,3 @@
   # cxserver is the ContentTranslation server.
   cxserver/deploy:
     repository: cxserver/deploy
-
diff --git a/hieradata/labs/deployment-prep/common.yaml 
b/hieradata/labs/deployment-prep/common.yaml
index 6a1ae68..f5c4d3d 100644
--- a/hieradata/labs/deployment-prep/common.yaml
+++ b/hieradata/labs/deployment-prep/common.yaml
@@ -205,18 +205,13 @@
 
   phabricator:
     trusted_group: project-%{::labsproject}
-    key_fingerprint: 39:b3:2c:a7:b2:80:65:ff:0c:97:e1:22:88:6c:59:10
-    key_secret: phabricator/phab_deploy_private_key
 
   eventlogging:
     trusted_group: project-%{::labsproject}
-    key_fingerprint: 02:9b:99:e2:f0:16:70:a3:d2:5a:e6:02:a3:73:0e:b0
 
   deploy-service:
     trusted_group: deploy-service
-    key_fingerprint: 6d:54:92:8b:39:10:f5:9b:84:40:36:ef:3c:9a:6d:d8
-    key_file: servicedeploy_rsa
-
+    key_name: servicedeploy
 
 # deployment-prep scap::source declarations.  These are created
 # by the scap::server class.  Each source listed here
diff --git a/modules/eventlogging/manifests/deployment/target.pp 
b/modules/eventlogging/manifests/deployment/target.pp
index 07a46ea..6ecd1ae 100644
--- a/modules/eventlogging/manifests/deployment/target.pp
+++ b/modules/eventlogging/manifests/deployment/target.pp
@@ -41,11 +41,10 @@
     include eventlogging::dependencies
 
     scap::target { "eventlogging/${title}":
-        package_name      => $package_name,
-        deploy_user       => 'eventlogging',
-        public_key_source => 
"puppet:///modules/eventlogging/deployment/eventlogging_rsa.pub.${::realm}",
-        service_name      => $service_name,
-        sudo_rules        => $sudo_rules,
-        manage_user       => false,
+        package_name => $package_name,
+        deploy_user  => 'eventlogging',
+        service_name => $service_name,
+        sudo_rules   => $sudo_rules,
+        manage_user  => false,
     }
 }
diff --git a/modules/keyholder/files/keyholder 
b/modules/keyholder/files/keyholder
index 942bbc1..77c39a1 100755
--- a/modules/keyholder/files/keyholder
+++ b/modules/keyholder/files/keyholder
@@ -25,8 +25,15 @@
   exit 1
 }
 
+#is_private_key() {
+#    [ -f "$1" ] && /usr/bin/openssl rsa -in "$1" -text -noout | \
+#     /bin/grep -o "[0-9]* bit" 1>/dev/null 2>&1
+#}
 is_valid_private_key() {
-  # Check that $1 is a passphrase-protected private key file.
+  # on deployment-prep we allow unencrypted keys:
+  [ -f "$1" ] && [ -f "/etc/wmflabs-project" ] && return 0;
+
+  # on production, check that $1 is a password-protected rsa private key file.
   [ -f "$1" ] && /usr/bin/openssl rsa -in "$1" -check -pubout -passin pass: 
2>&1 | \
     /bin/grep -q "bad password"
 }
@@ -51,10 +58,12 @@
     ;;
   arm)
     requires_root
+    KEYS=""
     for key in /etc/keyholder.d/*; do
       is_valid_private_key "$key" || ( echo "$key is not an acceptable key. 
Does it have a passphrase?"; continue )
-      $0 add "$key"
+      KEYS="$KEYS $key"
     done
+    $0 add $KEYS
     ;;
   disarm)
     requires_root
diff --git a/modules/keyholder/files/ssh-agent-proxy 
b/modules/keyholder/files/ssh-agent-proxy
index 134a8eb..5bd110c 100644
--- a/modules/keyholder/files/ssh-agent-proxy
+++ b/modules/keyholder/files/ssh-agent-proxy
@@ -88,15 +88,30 @@
     return string, offset + struct.calcsize(fmt)
 
 
+def get_key_fingerprints():
+    """Look up the key fingerprints for all keys held by keyholder"""
+    keymap = {}
+    lines = subprocess.check_output(['/usr/local/sbin/keyholder', 'status'])
+    lines = lines.splitlines()[2:]
+    for line in lines:
+        line = line.split(' ')
+        fingerprint = line[2]
+        path = line[3].split('/')
+        keyfile = path[-1]
+        keymap[keyfile] = fingerprint
+    return keymap
+
 def get_key_perms(path):
     """Recursively walk `path`, loading YAML configuration files."""
     key_perms = {}
+    fingerprints = get_key_fingerprints()
     for fname in glob.glob(os.path.join(path, '*.y*ml')):
         with open(fname) as yml:
             for group, keys in yaml.safe_load(yml).items():
                 for key in keys:
-                    key = key.replace(':', '')
-                    key_perms.setdefault(key, set()).add(group)
+                    fingerprint = fingerprints[key]
+                    fingerprint.replace(':', '')
+                    key_perms.setdefault(fingerprint, set()).add(group)
     return key_perms
 
 
diff --git a/modules/keyholder/manifests/agent.pp 
b/modules/keyholder/manifests/agent.pp
index 8cdc9de..7733d0a 100644
--- a/modules/keyholder/manifests/agent.pp
+++ b/modules/keyholder/manifests/agent.pp
@@ -7,59 +7,49 @@
 # [*name*]
 #   Used for service names, socket names, and default key name
 #
-# [*key_file*]
-#   The name of the key file stored in puppet private
-#   Should exist prior to running a defined resource
-#
 # [*trusted_group*]
 #   The name or GID of the trusted user group with which the agent
 #   should be shared. It is the caller's responsibility to ensure
 #   the group exists. An array of group identifiers can also be provided
 #   to allow access by multiple groups.
 #
-# [*key_fingerprint*]
-#   Fingerprint of the public half of the private keyfile specified
-#   by $key_file
+# [*ensure*]
+#   If 'present', config will be enabled; if 'absent', disabled.
+#   The default is 'present'.
 #
 # === Examples
 #
 #  keyholder::agent { 'mwdeploy':
-#      key_file         => 'mwdeploy_key_rsa',
 #      trusted_group   => ['wikidev', 'mwdeploy'],
-#      key_fingerprint => '00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00'
-#      require         => Group['wikidev'],
 #  }
 #
 define keyholder::agent(
     $trusted_group,
-    $key_fingerprint,
-    $key_file = "${name}_rsa",
-    $key_content = undef,
-    $key_secret = undef,
+    $ensure = 'present',
+    $key_name = $title
 ) {
+    validate_ensure($ensure)
+
     require ::keyholder
     require ::keyholder::monitoring
 
-    file { "/etc/keyholder-auth.d/${name}.yml":
-        content => inline_template("---\n<% [*@trusted_group].each do |g| 
%><%= g %>: ['<%= @key_fingerprint %>']\n<% end %>"),
+    $key_name_safe = regsubst($key_name, '\W', '_', 'G')
+    $key_content = secret("keyholder/${key_name_safe}")
+
+
+    file { "/etc/keyholder.d/${key_name_safe}":
+        ensure  => $ensure,
+        content => $key_content,
         owner   => 'root',
         group   => 'keyholder',
         mode    => '0440',
     }
 
-    # lint:ignore:puppet_url_without_modules
-    if $key_content {
-        keyholder::private_key { $key_file:
-            content  => $key_content,
-        }
-    } elsif $key_secret {
-        keyholder::private_key { $key_file:
-            content => secret($key_secret)
-        }
-    } else {
-        keyholder::private_key { $key_file:
-            source  => "puppet:///private/ssh/tin/${key_file}",
-        }
+    file { "/etc/keyholder-auth.d/${key_name_safe}.yml":
+        ensure  => $ensure,
+        content => inline_template("---\n<%= [*@trusted_group].map { |g| 
\"#{g}: [#{@key_name_safe}]\" }.join(\"\\n\") %>\n"),
+        owner   => 'root',
+        group   => 'keyholder',
+        mode    => '0440',
     }
-    # lint:endignore
 }
diff --git a/modules/keyholder/manifests/private_key.pp 
b/modules/keyholder/manifests/private_key.pp
deleted file mode 100644
index 5c06ebf..0000000
--- a/modules/keyholder/manifests/private_key.pp
+++ /dev/null
@@ -1,50 +0,0 @@
-# == Define: keyholder::private_key
-#
-# Provisions a private key file in /etc/keyholder.d.
-#
-# === Parameters
-#
-# [*ensure*]
-#   If 'present', config will be enabled; if 'absent', disabled.
-#   The default is 'present'.
-#
-# [*content*]
-#   If defined, will be used as the content of the key file.
-#   Undefined by default. Mutually exclusive with 'source'.
-#
-# [*source*]
-#   Path to key file. Undefined by default.
-#   Mutually exclusive with 'content'.
-#
-# === Examples
-#
-#  keyholder::private_key { 'mwdeploy_rsa':
-#    ensure => present,
-#    content => secret('ssh/tin/mwdeploy_rsa'),
-#  }
-#
-define keyholder::private_key(
-    $ensure  = present,
-    $content = undef,
-    $source  = undef,
-) {
-    validate_ensure($ensure)
-
-    if $source == undef and $content == undef  {
-        fail('you must provide either "source" or "content"')
-    }
-    if $source != undef and $content != undef  {
-        fail('"source" and "content" are mutually exclusive')
-    }
-
-    $title_safe  = regsubst($title, '\W', '_', 'G')
-
-    file { "/etc/keyholder.d/${title_safe}":
-        ensure  => $ensure,
-        content => $content,
-        source  => $source,
-        owner   => 'root',
-        group   => 'keyholder',
-        mode    => '0440',
-    }
-}
diff --git a/modules/phabricator/manifests/deployment/target.pp 
b/modules/phabricator/manifests/deployment/target.pp
deleted file mode 100644
index 0cf7ce4..0000000
--- a/modules/phabricator/manifests/deployment/target.pp
+++ /dev/null
@@ -1,18 +0,0 @@
-# == Class phabricator::deployment::target
-# This sets up sudo rules and the deploy_user for phabricator deployments with
-# scap3.
-
-class phabricator::deployment::target(
-  $deploy_user,
-  $deploy_key,
-  $deploy_target= 'phabricator/deployment',
-) {
-    scap::target { $deploy_target:
-        deploy_user       => $deploy_user,
-        public_key_source => $deploy_key,
-        sudo_rules        => [
-            'ALL=(root) NOPASSWD: /usr/sbin/service phd *',
-            'ALL=(root) NOPASSWD: /usr/sbin/service apache2 *',
-        ]
-    }
-}
diff --git a/modules/phabricator/manifests/init.pp 
b/modules/phabricator/manifests/init.pp
index 0d537fd..7e8f4d1 100644
--- a/modules/phabricator/manifests/init.pp
+++ b/modules/phabricator/manifests/init.pp
@@ -65,7 +65,7 @@
     $serveralias      = '',
     $deploy_user      = 'phab-deploy',
     $deploy_target    = 'phabricator/deployment',
-    $deploy_key       = 
"puppet:///modules/phabricator/phab-deploy-key.${::realm}",
+    $deploy_key       = 'phabricator',
 ) {
 
     $deploy_root = "/srv/deployment/${deploy_target}"
@@ -134,10 +134,13 @@
         }
     }
 
-    class { '::phabricator::deployment::target':
-        deploy_user   => $deploy_user,
-        deploy_key    => $deploy_key,
-        deploy_target => $deploy_target,
+    scap::target { $deploy_target:
+        deploy_user => $deploy_user,
+        deploy_key  => $deploy_key,
+        sudo_rules  => [
+            'ALL=(root) NOPASSWD: /usr/sbin/service phd *',
+            'ALL=(root) NOPASSWD: /usr/sbin/service apache2 *',
+        ]
     }
 
     file { $phabdir:
diff --git a/modules/role/manifests/deployment/mediawiki.pp 
b/modules/role/manifests/deployment/mediawiki.pp
index 18d34bd..f203d1b 100644
--- a/modules/role/manifests/deployment/mediawiki.pp
+++ b/modules/role/manifests/deployment/mediawiki.pp
@@ -3,7 +3,6 @@
 class role::deployment::mediawiki(
     $keyholder_user = 'mwdeploy',
     $keyholder_group = ['wikidev', 'mwdeploy'],
-    $key_fingerprint = 'f5:18:a3:44:77:a2:31:23:cb:7b:44:e1:4b:45:27:11',
     ) {
 
     # All needed classes for deploying mediawiki
@@ -18,7 +17,6 @@
 
     keyholder::agent { $keyholder_user:
         trusted_group   => $keyholder_group,
-        key_fingerprint => $key_fingerprint,
     }
 
     # Wikitech credentials file
diff --git a/modules/role/manifests/snapshot/deployment.pp 
b/modules/role/manifests/snapshot/deployment.pp
index c504ae0..19391db 100644
--- a/modules/role/manifests/snapshot/deployment.pp
+++ b/modules/role/manifests/snapshot/deployment.pp
@@ -1,7 +1,8 @@
+# Defines snapshot data dump deployment target(s)
 class role::snapshot::deployment {
     scap::target { 'dumps/dumps':
-        deploy_user       => 'datasets',
-        public_key_source => 
'puppet:///modules/snapshots/deployment/dumpsdeploy_rsa.pub',
-        manage_user       => false,
+        deploy_user => 'datasets',
+        manage_user => false,
+        key_name    => 'dumps',
     }
 }
diff --git a/modules/scap/manifests/target.pp b/modules/scap/manifests/target.pp
index ff3f67c..7f7f9f6 100644
--- a/modules/scap/manifests/target.pp
+++ b/modules/scap/manifests/target.pp
@@ -10,9 +10,13 @@
 # [*deploy_user*]
 #   user that will be used for deployments
 #
-# [*public_key_source*]
-#   puppet source argument to pass to ssh::userkey for installing
-#   $deploy_user's public ssh key.
+# [*key_name*]
+#   The name of a keyholder ssh key used to access this deployment target.
+#   This should correspond to a key which is defined in keyholder::agent
+#   (which are defined by hiera data in common::scap::server)
+#   Warning: If key_name is left undefined, then you must define the correct
+#   ssh::userkey for your deploy_user so that scap can connect to the target
+#   from the deployment server with a corresponding key in keyholder.
 #
 # [*service_name*]
 #   service name that should be allowed to be restarted via sudo by
@@ -34,18 +38,17 @@
 #
 #   scap::target { 'mockbase':
 #       deploy_user => 'deploy-mockbase',
-#       public_key_source => 'puppet://modules/mockbase/deploy-test_rsa.pub'
+#       key_name => 'deploy-mockbase',
 #   }
 #
 #   scap::target { 'eventlogging/eventlogging':
 #       deploy_user => 'eventlogging',
-#       public_key_source => 
"puppet:///modules/eventlogging/deployment/eventlogging_rsa.pub.${::realm}",
 #       manage_user => false,
 #   }
 #
 define scap::target(
     $deploy_user,
-    $public_key_source,
+    $key_name = undef,
     $service_name = undef,
     $package_name = $title,
     $manage_user = true,
@@ -65,7 +68,7 @@
         Group[$deploy_user] -> Scap::Target[$title]
     }
 
-    if $manage_user and !defined(User[$deploy_user]) {
+    if $manage_user {
         user { $deploy_user:
             ensure     => present,
             shell      => '/bin/bash',
@@ -75,6 +78,20 @@
         }
     } else {
         User[$deploy_user] -> Scap::Target[$title]
+    }
+
+    if $key_name and !defined(Ssh::Userkey[$deploy_user]){
+        ssh::userkey { $deploy_user:
+            ensure  => 'present',
+            content => secret("keyholder/${key_name}.pub"),
+        }
+    } else {
+        if !defined(Ssh::Userkey[$deploy_user]) {
+            # warning for services which manage their own user but forget to
+            # define the key.
+            info("Scap will not be able to deploy this target until you define 
\
+                  the ssh::userkey for user '${deploy_user}'")
+        }
     }
 
     if $::realm == 'labs' {
@@ -96,12 +113,6 @@
                   owner => $deploy_user}],
         provider        => 'scap3',
         require         => [Package['scap'], User[$deploy_user]],
-    }
-
-    if !defined(Ssh::Userkey[$deploy_user]) {
-        ssh::userkey { $deploy_user:
-            source => $public_key_source,
-        }
     }
 
     # XXX: Temporary work-around for switching services from Trebuchet to Scap3
diff --git a/modules/service/manifests/node.pp 
b/modules/service/manifests/node.pp
index 0fa5104..b40a777 100644
--- a/modules/service/manifests/node.pp
+++ b/modules/service/manifests/node.pp
@@ -75,7 +75,8 @@
 #  crashes. Default: true
 #
 # [*deployment*]
-#   If this value is set to 'scap3' then deploy via scap3, otherwise, use 
trebuchet
+#   If this value is set to 'scap3' then deploy via scap3, otherwise,
+#   use trebuchet
 #   Default: undef
 #
 # [*deployment_user*]
@@ -130,11 +131,12 @@
     case $deployment {
         'scap3': {
             if ! defined(Service::Deploy::Trebuchet[$repo]) {
-                service::deploy::scap{ $repo:
+                scap::target { $repo:
                     service_name => $title,
-                    user         => $deployment_user,
-                    before       => Base::Service_unit[$title],
+                    key_name     => 'servicedeploy',
+                    deploy_user  => $deployment_user,
                     manage_user  => $deployment_manage_user,
+                    before       => Base::Service_unit[$title],
                 }
             }
         }
diff --git a/modules/zotero/manifests/init.pp b/modules/zotero/manifests/init.pp
index 85537c5..d7541b9 100644
--- a/modules/zotero/manifests/init.pp
+++ b/modules/zotero/manifests/init.pp
@@ -34,17 +34,15 @@
     }
 
     scap::target { 'zotero/translators':
-        deploy_user       => 'deploy-service',
-        public_key_source => 'puppet:///modules/service/servicedeploy_rsa.pub',
-        service_name      => 'zotero',
-        before            => Service['zotero'],
+        deploy_user  => 'deploy-service',
+        service_name => 'zotero',
+        before       => Service['zotero'],
     }
 
     scap::target { 'zotero/translation-server':
-        deploy_user       => 'deploy-service',
-        public_key_source => 'puppet:///modules/service/servicedeploy_rsa.pub',
-        service_name      => 'zotero',
-        before            => Service['zotero'],
+        deploy_user  => 'deploy-service',
+        service_name => 'zotero',
+        before       => Service['zotero'],
     }
 
     # 
/srv/deployment/zotero/translation-server/defaults/preferences/defaults.js

-- 
To view, visit https://gerrit.wikimedia.org/r/289236
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: Id298a3e0f12e31afd7ea83970e192330ffbd4243
Gerrit-PatchSet: 1
Gerrit-Project: operations/puppet
Gerrit-Branch: production
Gerrit-Owner: 20after4 <mmod...@wikimedia.org>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to