puppetserver-ca 1.0.0 → 1.1.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.
- checksums.yaml +4 -4
 - data/README.md +46 -2
 - data/lib/puppetserver/ca/action/generate.rb +117 -20
 - data/lib/puppetserver/ca/action/list.rb +5 -1
 - data/lib/puppetserver/ca/config/puppet.rb +2 -16
 - data/lib/puppetserver/ca/config/puppetserver.rb +1 -3
 - data/lib/puppetserver/ca/local_certificate_authority.rb +53 -15
 - data/lib/puppetserver/ca/utils/config.rb +13 -1
 - data/lib/puppetserver/ca/version.rb +1 -1
 - metadata +2 -2
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
2 
     | 
    
         
             
            SHA1:
         
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: 9e9242f6653c1f428f154759eaeeae5d45860683
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: 08769d2347f84fc0c5b29dcc8e8fe4a5272c3674
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: 247107b319de6f2c00a62b0bdb9e03f4c4ff694dca4e319d9c5f88d251c800de91b68b504fb92c4d4fabf7e94110935f2fcc200cde320374bc7bf488f33d37a1
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: d3517342dad610a789ef54b26d17812581332abd69a61e70fd9063237820fdc0e69062557649c66ed7d92c0321922d94a28434ede370209c8de3a6285f0a4fca
         
     | 
    
        data/README.md
    CHANGED
    
    | 
         @@ -13,8 +13,52 @@ You may install it yourself with: 
     | 
|
| 
       13 
13 
     | 
    
         | 
| 
       14 
14 
     | 
    
         
             
            ## Usage
         
     | 
| 
       15 
15 
     | 
    
         | 
| 
       16 
     | 
    
         
            -
             
     | 
| 
       17 
     | 
    
         
            -
             
     | 
| 
      
 16 
     | 
    
         
            +
            For initial CA setup, we provide two options. These need to be run before starting
         
     | 
| 
      
 17 
     | 
    
         
            +
            Puppet Server for the first time.
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
            To set up a default CA, with a self-signed root cert and an intermediate signing cert:
         
     | 
| 
      
 20 
     | 
    
         
            +
            ```
         
     | 
| 
      
 21 
     | 
    
         
            +
            puppetserver ca setup
         
     | 
| 
      
 22 
     | 
    
         
            +
            ```
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
            To import a custom CA:
         
     | 
| 
      
 25 
     | 
    
         
            +
            ```
         
     | 
| 
      
 26 
     | 
    
         
            +
            puppetserver ca import --cert-bundle certs.pem --crl-chain crls.pem --private-key ca_key.pem
         
     | 
| 
      
 27 
     | 
    
         
            +
            ```
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
            The remaining actions provided by this gem require a running Puppet Server, since
         
     | 
| 
      
 30 
     | 
    
         
            +
            it primarily uses the CA's API endpoints to do its work. The following examples
         
     | 
| 
      
 31 
     | 
    
         
            +
            assume that you are using the gem packaged within Puppet Server.
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
            To sign a pending certificate request:
         
     | 
| 
      
 34 
     | 
    
         
            +
            ```
         
     | 
| 
      
 35 
     | 
    
         
            +
            puppetserver ca sign --certname foo.example.com
         
     | 
| 
      
 36 
     | 
    
         
            +
            ```
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
            To list certificates and CSRs:
         
     | 
| 
      
 39 
     | 
    
         
            +
            ```
         
     | 
| 
      
 40 
     | 
    
         
            +
            puppetserver ca list --all
         
     | 
| 
      
 41 
     | 
    
         
            +
            ```
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
            To revoke a signed certificate:
         
     | 
| 
      
 44 
     | 
    
         
            +
            ```
         
     | 
| 
      
 45 
     | 
    
         
            +
            puppetserver ca revoke --certname foo.example.com
         
     | 
| 
      
 46 
     | 
    
         
            +
            ```
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
            To revoke the cert and clean up all SSL files for a given certname:
         
     | 
| 
      
 49 
     | 
    
         
            +
            ```
         
     | 
| 
      
 50 
     | 
    
         
            +
            puppetserver ca clean --certname foo.example.com
         
     | 
| 
      
 51 
     | 
    
         
            +
            ```
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
            To create a new keypair and certificate for a certname:
         
     | 
| 
      
 54 
     | 
    
         
            +
            ```
         
     | 
| 
      
 55 
     | 
    
         
            +
            puppetserver ca generate --certname foo.example.com
         
     | 
| 
      
 56 
     | 
    
         
            +
            ```
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
            For more details, see the help output:
         
     | 
| 
      
 59 
     | 
    
         
            +
            ```
         
     | 
| 
      
 60 
     | 
    
         
            +
            puppetserver ca --help
         
     | 
| 
      
 61 
     | 
    
         
            +
            ```
         
     | 
| 
       18 
62 
     | 
    
         | 
| 
       19 
63 
     | 
    
         
             
            This code in this project is licensed under the Apache Software License v2,
         
     | 
| 
       20 
64 
     | 
    
         
             
            please see the included [License](https://github.com/puppetlabs/puppetserver-ca-cli/blob/master/LICENSE.md)
         
     | 
| 
         @@ -1,9 +1,12 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            require 'puppetserver/ca/utils/cli_parsing'
         
     | 
| 
       2 
2 
     | 
    
         
             
            require 'puppetserver/ca/host'
         
     | 
| 
       3 
3 
     | 
    
         
             
            require 'puppetserver/ca/certificate_authority'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'puppetserver/ca/local_certificate_authority'
         
     | 
| 
      
 5 
     | 
    
         
            +
            require 'puppetserver/ca/x509_loader'
         
     | 
| 
       4 
6 
     | 
    
         
             
            require 'puppetserver/ca/config/puppet'
         
     | 
| 
       5 
7 
     | 
    
         
             
            require 'puppetserver/ca/utils/file_system'
         
     | 
| 
       6 
8 
     | 
    
         
             
            require 'puppetserver/ca/utils/signing_digest'
         
     | 
| 
      
 9 
     | 
    
         
            +
            require 'puppetserver/ca/utils/config'
         
     | 
| 
       7 
10 
     | 
    
         | 
| 
       8 
11 
     | 
    
         
             
            module Puppetserver
         
     | 
| 
       9 
12 
     | 
    
         
             
              module Ca
         
     | 
| 
         @@ -20,13 +23,27 @@ module Puppetserver 
     | 
|
| 
       20 
23 
     | 
    
         
             
                    BANNER = <<-BANNER
         
     | 
| 
       21 
24 
     | 
    
         
             
            Usage:
         
     | 
| 
       22 
25 
     | 
    
         
             
              puppetserver ca generate [--help]
         
     | 
| 
       23 
     | 
    
         
            -
              puppetserver ca generate  
     | 
| 
      
 26 
     | 
    
         
            +
              puppetserver ca generate --certname NAME[,NAME] [--config PATH]
         
     | 
| 
       24 
27 
     | 
    
         
             
                                       [--subject-alt-names NAME[,NAME]]
         
     | 
| 
      
 28 
     | 
    
         
            +
                                       [--ca-client]
         
     | 
| 
       25 
29 
     | 
    
         | 
| 
       26 
30 
     | 
    
         
             
            Description:
         
     | 
| 
       27 
31 
     | 
    
         
             
            Generates a new certificate signed by the intermediate CA
         
     | 
| 
       28 
32 
     | 
    
         
             
            and stores generated keys and certs on disk.
         
     | 
| 
       29 
33 
     | 
    
         | 
| 
      
 34 
     | 
    
         
            +
            If the `--ca-client` flag is passed, the cert will be generated
         
     | 
| 
      
 35 
     | 
    
         
            +
            offline, without using Puppet Server's signing code, and will add
         
     | 
| 
      
 36 
     | 
    
         
            +
            a special extension authorizing it to talk to the CA API. This can
         
     | 
| 
      
 37 
     | 
    
         
            +
            be used for regenerating the master's host cert, or for manually
         
     | 
| 
      
 38 
     | 
    
         
            +
            setting up other nodes to be CA clients. Do not distribute certs
         
     | 
| 
      
 39 
     | 
    
         
            +
            generated this way to any node that you do not intend to have
         
     | 
| 
      
 40 
     | 
    
         
            +
            administrative access to the CA (e.g. the ability to sign a cert).
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
            Since the `--ca-client` causes a cert to be generated offline, it
         
     | 
| 
      
 43 
     | 
    
         
            +
            should ONLY be used when Puppet Server is NOT running, to avoid
         
     | 
| 
      
 44 
     | 
    
         
            +
            conflicting with the actions of the CA service. This will be
         
     | 
| 
      
 45 
     | 
    
         
            +
            mandatory in a future release.
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
       30 
47 
     | 
    
         
             
            To determine the target location, the default puppet.conf
         
     | 
| 
       31 
48 
     | 
    
         
             
            is consulted for custom values. If using a custom puppet.conf
         
     | 
| 
       32 
49 
     | 
    
         
             
            provide it with the --config flag
         
     | 
| 
         @@ -56,6 +73,11 @@ BANNER 
     | 
|
| 
       56 
73 
     | 
    
         
             
                                'Subject alternative names for the generated cert') do |sans|
         
     | 
| 
       57 
74 
     | 
    
         
             
                          parsed['subject-alt-names'] = sans
         
     | 
| 
       58 
75 
     | 
    
         
             
                        end
         
     | 
| 
      
 76 
     | 
    
         
            +
                        opts.on('--ca-client',
         
     | 
| 
      
 77 
     | 
    
         
            +
                                'Whether this cert will be used to request CA actions.\
         
     | 
| 
      
 78 
     | 
    
         
            +
                                Causes the cert to be generated offline.') do |ca_client|
         
     | 
| 
      
 79 
     | 
    
         
            +
                          parsed['ca-client'] = true
         
     | 
| 
      
 80 
     | 
    
         
            +
                        end
         
     | 
| 
       59 
81 
     | 
    
         
             
                      end
         
     | 
| 
       60 
82 
     | 
    
         
             
                    end
         
     | 
| 
       61 
83 
     | 
    
         | 
| 
         @@ -103,27 +125,66 @@ BANNER 
     | 
|
| 
       103 
125 
     | 
    
         | 
| 
       104 
126 
     | 
    
         
             
                      # Load, resolve, and validate puppet config settings
         
     | 
| 
       105 
127 
     | 
    
         
             
                      settings_overrides = {}
         
     | 
| 
       106 
     | 
    
         
            -
                      # Since puppet expects the key to be called 'dns_alt_names', we need to use that here
         
     | 
| 
       107 
     | 
    
         
            -
                      # to ensure that the overriding works correctly.
         
     | 
| 
       108 
     | 
    
         
            -
                      settings_overrides[:dns_alt_names] = input['subject-alt-names'] unless input['subject-alt-names'].empty?
         
     | 
| 
       109 
128 
     | 
    
         
             
                      puppet = Config::Puppet.new(config_path)
         
     | 
| 
       110 
129 
     | 
    
         
             
                      puppet.load(settings_overrides)
         
     | 
| 
       111 
130 
     | 
    
         
             
                      return 1 if CliParsing.handle_errors(@logger, puppet.errors)
         
     | 
| 
       112 
131 
     | 
    
         | 
| 
      
 132 
     | 
    
         
            +
                      # We don't want generate to respect the alt names setting, since it is usually
         
     | 
| 
      
 133 
     | 
    
         
            +
                      # used to generate certs for other nodes
         
     | 
| 
      
 134 
     | 
    
         
            +
                      alt_names = input['subject-alt-names']
         
     | 
| 
      
 135 
     | 
    
         
            +
             
     | 
| 
       113 
136 
     | 
    
         
             
                      # Load most secure signing digest we can for csr signing.
         
     | 
| 
       114 
137 
     | 
    
         
             
                      signer = SigningDigest.new
         
     | 
| 
       115 
138 
     | 
    
         
             
                      return 1 if CliParsing.handle_errors(@logger, signer.errors)
         
     | 
| 
       116 
139 
     | 
    
         | 
| 
       117 
140 
     | 
    
         
             
                      # Generate and save certs and associated keys
         
     | 
| 
       118 
     | 
    
         
            -
                       
     | 
| 
      
 141 
     | 
    
         
            +
                      if input['ca-client']
         
     | 
| 
      
 142 
     | 
    
         
            +
                        all_passed = generate_authorized_certs(certnames, alt_names, puppet.settings, signer.digest)
         
     | 
| 
      
 143 
     | 
    
         
            +
                      else
         
     | 
| 
      
 144 
     | 
    
         
            +
                        all_passed = generate_certs(certnames, alt_names, puppet.settings, signer.digest)
         
     | 
| 
      
 145 
     | 
    
         
            +
                      end
         
     | 
| 
       119 
146 
     | 
    
         
             
                      return all_passed ? 0 : 1
         
     | 
| 
       120 
147 
     | 
    
         
             
                    end
         
     | 
| 
       121 
148 
     | 
    
         | 
| 
      
 149 
     | 
    
         
            +
                    # Certs authorized to talk to the CA API need to be signed offline,
         
     | 
| 
      
 150 
     | 
    
         
            +
                    # in order to securely add the special auth extension.
         
     | 
| 
      
 151 
     | 
    
         
            +
                    def generate_authorized_certs(certnames, alt_names, settings, digest)
         
     | 
| 
      
 152 
     | 
    
         
            +
                      # Make sure we have all the directories where we will be writing files
         
     | 
| 
      
 153 
     | 
    
         
            +
                      FileSystem.ensure_dirs([settings[:ssldir],
         
     | 
| 
      
 154 
     | 
    
         
            +
                                              settings[:certdir],
         
     | 
| 
      
 155 
     | 
    
         
            +
                                              settings[:privatekeydir],
         
     | 
| 
      
 156 
     | 
    
         
            +
                                              settings[:publickeydir]])
         
     | 
| 
      
 157 
     | 
    
         
            +
             
     | 
| 
      
 158 
     | 
    
         
            +
                      ca = Puppetserver::Ca::LocalCertificateAuthority.new(digest, settings)
         
     | 
| 
      
 159 
     | 
    
         
            +
                      ca_cert, ca_key = ca.load_ca
         
     | 
| 
      
 160 
     | 
    
         
            +
                      return false if CliParsing.handle_errors(@logger, ca.errors)
         
     | 
| 
      
 161 
     | 
    
         
            +
             
     | 
| 
      
 162 
     | 
    
         
            +
                      passed = certnames.map do |certname|
         
     | 
| 
      
 163 
     | 
    
         
            +
                        errors = check_for_existing_ssl_files(certname, settings)
         
     | 
| 
      
 164 
     | 
    
         
            +
                        next false if CliParsing.handle_errors(@logger, errors)
         
     | 
| 
      
 165 
     | 
    
         
            +
             
     | 
| 
      
 166 
     | 
    
         
            +
                        current_alt_names = process_alt_names(alt_names, certname)
         
     | 
| 
      
 167 
     | 
    
         
            +
             
     | 
| 
      
 168 
     | 
    
         
            +
                        # For certs signed offline, any alt names are added directly to the cert,
         
     | 
| 
      
 169 
     | 
    
         
            +
                        # rather than to the CSR.
         
     | 
| 
      
 170 
     | 
    
         
            +
                        key, csr = generate_key_csr(certname, settings, digest)
         
     | 
| 
      
 171 
     | 
    
         
            +
                        next false unless csr
         
     | 
| 
      
 172 
     | 
    
         
            +
             
     | 
| 
      
 173 
     | 
    
         
            +
                        cert = ca.sign_authorized_cert(ca_key, ca_cert, csr, current_alt_names)
         
     | 
| 
      
 174 
     | 
    
         
            +
                        next false unless save_file(cert.to_pem, certname, settings[:certdir], "Certificate")
         
     | 
| 
      
 175 
     | 
    
         
            +
                        next false unless save_file(cert.to_pem, certname, settings[:signeddir], "Certificate")
         
     | 
| 
      
 176 
     | 
    
         
            +
                        next false unless save_keys(certname, settings, key)
         
     | 
| 
      
 177 
     | 
    
         
            +
                        ca.update_serial_file(cert.serial + 1)
         
     | 
| 
      
 178 
     | 
    
         
            +
                        true
         
     | 
| 
      
 179 
     | 
    
         
            +
                      end
         
     | 
| 
      
 180 
     | 
    
         
            +
                      passed.all?
         
     | 
| 
      
 181 
     | 
    
         
            +
                    end
         
     | 
| 
      
 182 
     | 
    
         
            +
             
     | 
| 
       122 
183 
     | 
    
         
             
                    # Generate csrs and keys, then submit them to CA, request for the CA to sign
         
     | 
| 
       123 
184 
     | 
    
         
             
                    # them, download the signed certificates from the CA, and finally save
         
     | 
| 
       124 
185 
     | 
    
         
             
                    # the signed certs and associated keys. Returns true if all certs were
         
     | 
| 
       125 
186 
     | 
    
         
             
                    # successfully created and saved.
         
     | 
| 
       126 
     | 
    
         
            -
                    def generate_certs(certnames, settings, digest)
         
     | 
| 
      
 187 
     | 
    
         
            +
                    def generate_certs(certnames, alt_names, settings, digest)
         
     | 
| 
       127 
188 
     | 
    
         
             
                      # Make sure we have all the directories where we will be writing files
         
     | 
| 
       128 
189 
     | 
    
         
             
                      FileSystem.ensure_dirs([settings[:ssldir],
         
     | 
| 
       129 
190 
     | 
    
         
             
                                              settings[:certdir],
         
     | 
| 
         @@ -133,13 +194,18 @@ BANNER 
     | 
|
| 
       133 
194 
     | 
    
         
             
                      ca = Puppetserver::Ca::CertificateAuthority.new(@logger, settings)
         
     | 
| 
       134 
195 
     | 
    
         | 
| 
       135 
196 
     | 
    
         
             
                      passed = certnames.map do |certname|
         
     | 
| 
       136 
     | 
    
         
            -
                         
     | 
| 
       137 
     | 
    
         
            -
                         
     | 
| 
       138 
     | 
    
         
            -
             
     | 
| 
       139 
     | 
    
         
            -
                         
     | 
| 
      
 197 
     | 
    
         
            +
                        errors = check_for_existing_ssl_files(certname, settings)
         
     | 
| 
      
 198 
     | 
    
         
            +
                        next false if CliParsing.handle_errors(@logger, errors)
         
     | 
| 
      
 199 
     | 
    
         
            +
             
     | 
| 
      
 200 
     | 
    
         
            +
                        current_alt_names = process_alt_names(alt_names, certname)
         
     | 
| 
      
 201 
     | 
    
         
            +
             
     | 
| 
      
 202 
     | 
    
         
            +
                        key, csr = generate_key_csr(certname, settings, digest, current_alt_names)
         
     | 
| 
      
 203 
     | 
    
         
            +
                        next false unless csr
         
     | 
| 
      
 204 
     | 
    
         
            +
                        next false unless ca.submit_certificate_request(certname, csr)
         
     | 
| 
      
 205 
     | 
    
         
            +
                        next false unless ca.sign_certs([certname])
         
     | 
| 
       140 
206 
     | 
    
         
             
                        if result = ca.get_certificate(certname)
         
     | 
| 
       141 
     | 
    
         
            -
                          save_file(result.body, certname, settings[:certdir], "Certificate")
         
     | 
| 
       142 
     | 
    
         
            -
                          save_keys(certname, settings, key)
         
     | 
| 
      
 207 
     | 
    
         
            +
                          next false unless save_file(result.body, certname, settings[:certdir], "Certificate")
         
     | 
| 
      
 208 
     | 
    
         
            +
                          next false unless save_keys(certname, settings, key)
         
     | 
| 
       143 
209 
     | 
    
         
             
                          true
         
     | 
| 
       144 
210 
     | 
    
         
             
                        else
         
     | 
| 
       145 
211 
     | 
    
         
             
                          false
         
     | 
| 
         @@ -148,14 +214,16 @@ BANNER 
     | 
|
| 
       148 
214 
     | 
    
         
             
                      passed.all?
         
     | 
| 
       149 
215 
     | 
    
         
             
                    end
         
     | 
| 
       150 
216 
     | 
    
         | 
| 
       151 
     | 
    
         
            -
                     
     | 
| 
      
 217 
     | 
    
         
            +
                    # For certs signed offline, any alt names are added directly to the cert,
         
     | 
| 
      
 218 
     | 
    
         
            +
                    # rather than to the CSR.
         
     | 
| 
      
 219 
     | 
    
         
            +
                    def generate_key_csr(certname, settings, digest, alt_names = '')
         
     | 
| 
       152 
220 
     | 
    
         
             
                      host = Puppetserver::Ca::Host.new(digest)
         
     | 
| 
       153 
221 
     | 
    
         
             
                      private_key = host.create_private_key(settings[:keylength])
         
     | 
| 
       154 
222 
     | 
    
         
             
                      extensions = []
         
     | 
| 
       155 
     | 
    
         
            -
                      if ! 
     | 
| 
      
 223 
     | 
    
         
            +
                      if !alt_names.empty?
         
     | 
| 
       156 
224 
     | 
    
         
             
                        ef = OpenSSL::X509::ExtensionFactory.new
         
     | 
| 
       157 
225 
     | 
    
         
             
                        extensions << ef.create_extension("subjectAltName",
         
     | 
| 
       158 
     | 
    
         
            -
                                                           
     | 
| 
      
 226 
     | 
    
         
            +
                                                          alt_names,
         
     | 
| 
       159 
227 
     | 
    
         
             
                                                          false)
         
     | 
| 
       160 
228 
     | 
    
         
             
                      end
         
     | 
| 
       161 
229 
     | 
    
         
             
                      csr = host.create_csr(name: certname,
         
     | 
| 
         @@ -169,15 +237,44 @@ BANNER 
     | 
|
| 
       169 
237 
     | 
    
         | 
| 
       170 
238 
     | 
    
         
             
                    def save_keys(certname, settings, key)
         
     | 
| 
       171 
239 
     | 
    
         
             
                      public_key = key.public_key
         
     | 
| 
       172 
     | 
    
         
            -
                      save_file(key, certname, settings[:privatekeydir], "Private key")
         
     | 
| 
       173 
     | 
    
         
            -
                      save_file(public_key, certname, settings[:publickeydir], "Public key")
         
     | 
| 
      
 240 
     | 
    
         
            +
                      return false unless save_file(key, certname, settings[:privatekeydir], "Private key")
         
     | 
| 
      
 241 
     | 
    
         
            +
                      return false unless save_file(public_key, certname, settings[:publickeydir], "Public key")
         
     | 
| 
      
 242 
     | 
    
         
            +
                      true
         
     | 
| 
       174 
243 
     | 
    
         
             
                    end
         
     | 
| 
       175 
244 
     | 
    
         | 
| 
       176 
245 
     | 
    
         
             
                    def save_file(content, certname, dir, type)
         
     | 
| 
       177 
246 
     | 
    
         
             
                      location = File.join(dir, "#{certname}.pem")
         
     | 
| 
       178 
     | 
    
         
            -
                       
     | 
| 
       179 
     | 
    
         
            -
             
     | 
| 
       180 
     | 
    
         
            -
             
     | 
| 
      
 247 
     | 
    
         
            +
                      if File.exist?(location)
         
     | 
| 
      
 248 
     | 
    
         
            +
                        @logger.err "#{type} #{certname}.pem already exists. Please delete it if you really want to regenerate it."
         
     | 
| 
      
 249 
     | 
    
         
            +
                        false
         
     | 
| 
      
 250 
     | 
    
         
            +
                      else
         
     | 
| 
      
 251 
     | 
    
         
            +
                        FileSystem.write_file(location, content, 0640)
         
     | 
| 
      
 252 
     | 
    
         
            +
                        @logger.inform "Successfully saved #{type.downcase} for #{certname} to #{location}"
         
     | 
| 
      
 253 
     | 
    
         
            +
                        true
         
     | 
| 
      
 254 
     | 
    
         
            +
                      end
         
     | 
| 
      
 255 
     | 
    
         
            +
                    end
         
     | 
| 
      
 256 
     | 
    
         
            +
             
     | 
| 
      
 257 
     | 
    
         
            +
                    def check_for_existing_ssl_files(certname, settings)
         
     | 
| 
      
 258 
     | 
    
         
            +
                      files = [ File.join(settings[:certdir], "#{certname}.pem"),
         
     | 
| 
      
 259 
     | 
    
         
            +
                                File.join(settings[:privatekeydir], "#{certname}.pem"),
         
     | 
| 
      
 260 
     | 
    
         
            +
                                File.join(settings[:publickeydir], "#{certname}.pem"),
         
     | 
| 
      
 261 
     | 
    
         
            +
                                File.join(settings[:signeddir], "#{certname}.pem"), ]
         
     | 
| 
      
 262 
     | 
    
         
            +
                      errors = Puppetserver::Ca::Utils::FileSystem.check_for_existing_files(files)
         
     | 
| 
      
 263 
     | 
    
         
            +
                      if !errors.empty?
         
     | 
| 
      
 264 
     | 
    
         
            +
                        errors << "Please delete these files if you really want to generate a new cert for #{certname}."
         
     | 
| 
      
 265 
     | 
    
         
            +
                      end
         
     | 
| 
      
 266 
     | 
    
         
            +
                      errors
         
     | 
| 
      
 267 
     | 
    
         
            +
                    end
         
     | 
| 
      
 268 
     | 
    
         
            +
             
     | 
| 
      
 269 
     | 
    
         
            +
                    def process_alt_names(alt_names, certname)
         
     | 
| 
      
 270 
     | 
    
         
            +
                      return '' if alt_names.empty?
         
     | 
| 
      
 271 
     | 
    
         
            +
             
     | 
| 
      
 272 
     | 
    
         
            +
                      current_alt_names = alt_names.dup
         
     | 
| 
      
 273 
     | 
    
         
            +
                      # When validating the cert, OpenSSL will ignore the CN field if
         
     | 
| 
      
 274 
     | 
    
         
            +
                      # altnames are present, so we need to ensure that the certname is
         
     | 
| 
      
 275 
     | 
    
         
            +
                      # also listed among the alt names.
         
     | 
| 
      
 276 
     | 
    
         
            +
                      current_alt_names += ",DNS:#{certname}"
         
     | 
| 
      
 277 
     | 
    
         
            +
                      current_alt_names = Puppetserver::Ca::Utils::Config.munge_alt_names(current_alt_names)
         
     | 
| 
       181 
278 
     | 
    
         
             
                    end
         
     | 
| 
       182 
279 
     | 
    
         
             
                  end
         
     | 
| 
       183 
280 
     | 
    
         
             
                end
         
     | 
| 
         @@ -96,8 +96,12 @@ Options: 
     | 
|
| 
       96 
96 
     | 
    
         
             
                      end
         
     | 
| 
       97 
97 
     | 
    
         | 
| 
       98 
98 
     | 
    
         
             
                      certs.each do |cert|
         
     | 
| 
      
 99 
     | 
    
         
            +
                        # In newer versions of the CA api we return subjcet_alt_names
         
     | 
| 
      
 100 
     | 
    
         
            +
                        # in addition to dns_alt_names, this field includes DNS alt
         
     | 
| 
      
 101 
     | 
    
         
            +
                        # names but also IP alt names.
         
     | 
| 
      
 102 
     | 
    
         
            +
                        alt_names = cert["subject_alt_names"] || cert["dns_alt_names"]
         
     | 
| 
       99 
103 
     | 
    
         
             
                        @logger.inform "    #{cert["name"]}".ljust(padded + 6) + " (SHA256) " + " #{cert["fingerprints"]["SHA256"]}" +
         
     | 
| 
       100 
     | 
    
         
            -
                                           ( 
     | 
| 
      
 104 
     | 
    
         
            +
                                           (alt_names.empty? ? "" : "\talt names: #{alt_names}")
         
     | 
| 
       101 
105 
     | 
    
         
             
                        end
         
     | 
| 
       102 
106 
     | 
    
         
             
                    end
         
     | 
| 
       103 
107 
     | 
    
         | 
| 
         @@ -22,8 +22,6 @@ module Puppetserver 
     | 
|
| 
       22 
22 
     | 
    
         
             
                    # A regex describing valid formats with groups for capturing the value and units
         
     | 
| 
       23 
23 
     | 
    
         
             
                    TTL_FORMAT = /^(\d+)(y|d|h|m|s)?$/
         
     | 
| 
       24 
24 
     | 
    
         | 
| 
       25 
     | 
    
         
            -
                    include Puppetserver::Ca::Utils::Config
         
     | 
| 
       26 
     | 
    
         
            -
             
     | 
| 
       27 
25 
     | 
    
         
             
                    def self.parse(config_path)
         
     | 
| 
       28 
26 
     | 
    
         
             
                      instance = new(config_path)
         
     | 
| 
       29 
27 
     | 
    
         
             
                      instance.load
         
     | 
| 
         @@ -49,7 +47,7 @@ module Puppetserver 
     | 
|
| 
       49 
47 
     | 
    
         
             
                    # start/stop it you must be root.
         
     | 
| 
       50 
48 
     | 
    
         
             
                    def user_specific_conf_dir
         
     | 
| 
       51 
49 
     | 
    
         
             
                      @user_specific_conf_dir ||=
         
     | 
| 
       52 
     | 
    
         
            -
                        if running_as_root?
         
     | 
| 
      
 50 
     | 
    
         
            +
                        if Puppetserver::Ca::Utils::Config.running_as_root?
         
     | 
| 
       53 
51 
     | 
    
         
             
                          '/etc/puppetlabs/puppet'
         
     | 
| 
       54 
52 
     | 
    
         
             
                        else
         
     | 
| 
       55 
53 
     | 
    
         
             
                          "#{ENV['HOME']}/.puppetlabs/etc/puppet"
         
     | 
| 
         @@ -161,7 +159,7 @@ module Puppetserver 
     | 
|
| 
       161 
159 
     | 
    
         
             
                      # Some special cases where we need to manipulate config settings:
         
     | 
| 
       162 
160 
     | 
    
         
             
                      settings[:ca_ttl] = munge_ttl_setting(settings[:ca_ttl])
         
     | 
| 
       163 
161 
     | 
    
         
             
                      settings[:certificate_revocation] = parse_crl_usage(settings[:certificate_revocation])
         
     | 
| 
       164 
     | 
    
         
            -
                      settings[:subject_alt_names] = munge_alt_names(settings[:subject_alt_names])
         
     | 
| 
      
 162 
     | 
    
         
            +
                      settings[:subject_alt_names] = Puppetserver::Ca::Utils::Config.munge_alt_names(settings[:subject_alt_names])
         
     | 
| 
       165 
163 
     | 
    
         
             
                      settings[:keylength] = settings[:keylength].to_i
         
     | 
| 
       166 
164 
     | 
    
         | 
| 
       167 
165 
     | 
    
         
             
                      settings.each do |key, value|
         
     | 
| 
         @@ -231,18 +229,6 @@ module Puppetserver 
     | 
|
| 
       231 
229 
     | 
    
         
             
                      end
         
     | 
| 
       232 
230 
     | 
    
         
             
                    end
         
     | 
| 
       233 
231 
     | 
    
         | 
| 
       234 
     | 
    
         
            -
                    def munge_alt_names(names)
         
     | 
| 
       235 
     | 
    
         
            -
                      raw_names = names.split(/\s*,\s*/).map(&:strip)
         
     | 
| 
       236 
     | 
    
         
            -
                      munged_names = raw_names.map do |name|
         
     | 
| 
       237 
     | 
    
         
            -
                        # Prepend the DNS tag if no tag was specified
         
     | 
| 
       238 
     | 
    
         
            -
                        if !name.start_with?("IP:") && !name.start_with?("DNS:")
         
     | 
| 
       239 
     | 
    
         
            -
                          "DNS:#{name}"
         
     | 
| 
       240 
     | 
    
         
            -
                        else
         
     | 
| 
       241 
     | 
    
         
            -
                          name
         
     | 
| 
       242 
     | 
    
         
            -
                        end
         
     | 
| 
       243 
     | 
    
         
            -
                      end.sort.uniq.join(", ")
         
     | 
| 
       244 
     | 
    
         
            -
                    end
         
     | 
| 
       245 
     | 
    
         
            -
             
     | 
| 
       246 
232 
     | 
    
         
             
                    def parse_crl_usage(setting)
         
     | 
| 
       247 
233 
     | 
    
         
             
                      case setting.to_s
         
     | 
| 
       248 
234 
     | 
    
         
             
                      when 'true', 'chain'
         
     | 
| 
         @@ -8,8 +8,6 @@ module Puppetserver 
     | 
|
| 
       8 
8 
     | 
    
         
             
                  # Puppetserver or any TK config service. Uses the ruby-hocon gem for parsing.
         
     | 
| 
       9 
9 
     | 
    
         
             
                  class PuppetServer
         
     | 
| 
       10 
10 
     | 
    
         | 
| 
       11 
     | 
    
         
            -
                    include Puppetserver::Ca::Utils::Config
         
     | 
| 
       12 
     | 
    
         
            -
             
     | 
| 
       13 
11 
     | 
    
         
             
                    def self.parse(config_path = nil)
         
     | 
| 
       14 
12 
     | 
    
         
             
                      instance = new(config_path)
         
     | 
| 
       15 
13 
     | 
    
         
             
                      instance.load
         
     | 
| 
         @@ -50,7 +48,7 @@ module Puppetserver 
     | 
|
| 
       50 
48 
     | 
    
         
             
                    # Note that Puppet Server runs as the [pe-]puppet user but to
         
     | 
| 
       51 
49 
     | 
    
         
             
                    # start/stop it you must be root.
         
     | 
| 
       52 
50 
     | 
    
         
             
                    def user_specific_ca_dir
         
     | 
| 
       53 
     | 
    
         
            -
                      if running_as_root?
         
     | 
| 
      
 51 
     | 
    
         
            +
                      if Puppetserver::Ca::Utils::Config.running_as_root?
         
     | 
| 
       54 
52 
     | 
    
         
             
                        '/etc/puppetlabs/puppetserver/ca'
         
     | 
| 
       55 
53 
     | 
    
         
             
                      else
         
     | 
| 
       56 
54 
     | 
    
         
             
                        "#{ENV['HOME']}/.puppetlabs/etc/puppetserver/ca"
         
     | 
| 
         @@ -1,4 +1,5 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            require 'puppetserver/ca/host'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'puppetserver/ca/utils/file_system'
         
     | 
| 
       2 
3 
     | 
    
         | 
| 
       3 
4 
     | 
    
         
             
            require 'openssl'
         
     | 
| 
       4 
5 
     | 
    
         | 
| 
         @@ -39,10 +40,11 @@ module Puppetserver 
     | 
|
| 
       39 
40 
     | 
    
         
             
                    @digest = digest
         
     | 
| 
       40 
41 
     | 
    
         
             
                    @host = Host.new(digest)
         
     | 
| 
       41 
42 
     | 
    
         
             
                    @settings = settings
         
     | 
| 
      
 43 
     | 
    
         
            +
                    @errors = []
         
     | 
| 
       42 
44 
     | 
    
         
             
                  end
         
     | 
| 
       43 
45 
     | 
    
         | 
| 
       44 
46 
     | 
    
         
             
                  def errors
         
     | 
| 
       45 
     | 
    
         
            -
                    @host.errors
         
     | 
| 
      
 47 
     | 
    
         
            +
                    @errors += @host.errors
         
     | 
| 
       46 
48 
     | 
    
         
             
                  end
         
     | 
| 
       47 
49 
     | 
    
         | 
| 
       48 
50 
     | 
    
         
             
                  def valid_until
         
     | 
| 
         @@ -62,6 +64,14 @@ module Puppetserver 
     | 
|
| 
       62 
64 
     | 
    
         
             
                                         format_time(cert.not_after), cert.subject]
         
     | 
| 
       63 
65 
     | 
    
         
             
                  end
         
     | 
| 
       64 
66 
     | 
    
         | 
| 
      
 67 
     | 
    
         
            +
                  def next_serial(serial_file)
         
     | 
| 
      
 68 
     | 
    
         
            +
                    if File.exist?(serial_file)
         
     | 
| 
      
 69 
     | 
    
         
            +
                      File.read(serial_file).to_i
         
     | 
| 
      
 70 
     | 
    
         
            +
                    else
         
     | 
| 
      
 71 
     | 
    
         
            +
                      1
         
     | 
| 
      
 72 
     | 
    
         
            +
                    end
         
     | 
| 
      
 73 
     | 
    
         
            +
                  end
         
     | 
| 
      
 74 
     | 
    
         
            +
             
     | 
| 
       65 
75 
     | 
    
         
             
                  def format_time(time)
         
     | 
| 
       66 
76 
     | 
    
         
             
                    time.strftime('%Y-%m-%dT%H:%M:%S%Z')
         
     | 
| 
       67 
77 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -73,33 +83,63 @@ module Puppetserver 
     | 
|
| 
       73 
83 
     | 
    
         
             
                                                          @settings[:hostpubkey])
         
     | 
| 
       74 
84 
     | 
    
         
             
                    if master_key
         
     | 
| 
       75 
85 
     | 
    
         
             
                      master_csr = @host.create_csr(name: @settings[:certname], key: master_key)
         
     | 
| 
       76 
     | 
    
         
            -
                       
     | 
| 
      
 86 
     | 
    
         
            +
                      if @settings[:subject_alt_names].empty?
         
     | 
| 
      
 87 
     | 
    
         
            +
                        alt_names = "DNS:puppet, DNS:#{@settings[:certname]}"
         
     | 
| 
      
 88 
     | 
    
         
            +
                      else
         
     | 
| 
      
 89 
     | 
    
         
            +
                        alt_names = @settings[:subject_alt_names]
         
     | 
| 
      
 90 
     | 
    
         
            +
                      end
         
     | 
| 
      
 91 
     | 
    
         
            +
             
     | 
| 
      
 92 
     | 
    
         
            +
                      master_cert = sign_authorized_cert(ca_key, ca_cert, master_csr, alt_names)
         
     | 
| 
       77 
93 
     | 
    
         
             
                    end
         
     | 
| 
       78 
94 
     | 
    
         | 
| 
       79 
95 
     | 
    
         
             
                    return master_key, master_cert
         
     | 
| 
       80 
96 
     | 
    
         
             
                  end
         
     | 
| 
       81 
97 
     | 
    
         | 
| 
       82 
     | 
    
         
            -
                   
     | 
| 
      
 98 
     | 
    
         
            +
                  # Used when generating certificates offline.
         
     | 
| 
      
 99 
     | 
    
         
            +
                  def load_ca
         
     | 
| 
      
 100 
     | 
    
         
            +
                    signing_cert = nil
         
     | 
| 
      
 101 
     | 
    
         
            +
                    key = nil
         
     | 
| 
      
 102 
     | 
    
         
            +
             
     | 
| 
      
 103 
     | 
    
         
            +
                    if File.exist?(@settings[:cacert]) && File.exist?(@settings[:cakey]) && File.exist?(@settings[:cacrl])
         
     | 
| 
      
 104 
     | 
    
         
            +
                      loader = Puppetserver::Ca::X509Loader.new(@settings[:cacert], @settings[:cakey], @settings[:cacrl])
         
     | 
| 
      
 105 
     | 
    
         
            +
                      if loader.errors.empty?
         
     | 
| 
      
 106 
     | 
    
         
            +
                        signing_cert = loader.certs[0]
         
     | 
| 
      
 107 
     | 
    
         
            +
                        key = loader.key
         
     | 
| 
      
 108 
     | 
    
         
            +
                      else
         
     | 
| 
      
 109 
     | 
    
         
            +
                        @errors += loader.errors
         
     | 
| 
      
 110 
     | 
    
         
            +
                      end
         
     | 
| 
      
 111 
     | 
    
         
            +
                    else
         
     | 
| 
      
 112 
     | 
    
         
            +
                      @errors << "CA not initialized. Please set up your CA before attempting to generate certs offline."
         
     | 
| 
      
 113 
     | 
    
         
            +
                    end
         
     | 
| 
      
 114 
     | 
    
         
            +
             
     | 
| 
      
 115 
     | 
    
         
            +
                    return signing_cert, key
         
     | 
| 
      
 116 
     | 
    
         
            +
                  end
         
     | 
| 
      
 117 
     | 
    
         
            +
             
     | 
| 
      
 118 
     | 
    
         
            +
                  def sign_authorized_cert(int_key, int_cert, csr, alt_names = '')
         
     | 
| 
       83 
119 
     | 
    
         
             
                    cert = OpenSSL::X509::Certificate.new
         
     | 
| 
       84 
120 
     | 
    
         
             
                    cert.public_key = csr.public_key
         
     | 
| 
       85 
121 
     | 
    
         
             
                    cert.subject = csr.subject
         
     | 
| 
       86 
122 
     | 
    
         
             
                    cert.issuer = int_cert.subject
         
     | 
| 
       87 
123 
     | 
    
         
             
                    cert.version = 2
         
     | 
| 
       88 
     | 
    
         
            -
                    cert.serial =  
     | 
| 
      
 124 
     | 
    
         
            +
                    cert.serial = next_serial(@settings[:serial])
         
     | 
| 
       89 
125 
     | 
    
         
             
                    cert.not_before = CERT_VALID_FROM
         
     | 
| 
       90 
126 
     | 
    
         
             
                    cert.not_after = valid_until
         
     | 
| 
       91 
127 
     | 
    
         | 
| 
       92 
128 
     | 
    
         
             
                    return unless add_custom_extensions(cert)
         
     | 
| 
       93 
129 
     | 
    
         | 
| 
       94 
130 
     | 
    
         
             
                    ef = extension_factory_for(int_cert, cert)
         
     | 
| 
       95 
     | 
    
         
            -
                     
     | 
| 
       96 
     | 
    
         
            -
             
     | 
| 
      
 131 
     | 
    
         
            +
                    add_authorized_extensions(cert, ef)
         
     | 
| 
      
 132 
     | 
    
         
            +
             
     | 
| 
      
 133 
     | 
    
         
            +
                    if !alt_names.empty?
         
     | 
| 
      
 134 
     | 
    
         
            +
                      add_subject_alt_names_extension(alt_names, cert, ef)
         
     | 
| 
      
 135 
     | 
    
         
            +
                    end
         
     | 
| 
      
 136 
     | 
    
         
            +
             
     | 
| 
       97 
137 
     | 
    
         
             
                    cert.sign(int_key, @digest)
         
     | 
| 
       98 
138 
     | 
    
         | 
| 
       99 
139 
     | 
    
         
             
                    cert
         
     | 
| 
       100 
140 
     | 
    
         
             
                  end
         
     | 
| 
       101 
141 
     | 
    
         | 
| 
       102 
     | 
    
         
            -
                  def  
     | 
| 
      
 142 
     | 
    
         
            +
                  def add_authorized_extensions(cert, ef)
         
     | 
| 
       103 
143 
     | 
    
         
             
                    MASTER_EXTENSIONS.each do |ext|
         
     | 
| 
       104 
144 
     | 
    
         
             
                      extension = ef.create_extension(*ext)
         
     | 
| 
       105 
145 
     | 
    
         
             
                      cert.add_extension(extension)
         
     | 
| 
         @@ -110,14 +150,8 @@ module Puppetserver 
     | 
|
| 
       110 
150 
     | 
    
         
             
                    cert.add_extension(cli_auth_ext)
         
     | 
| 
       111 
151 
     | 
    
         
             
                  end
         
     | 
| 
       112 
152 
     | 
    
         | 
| 
       113 
     | 
    
         
            -
                  def add_subject_alt_names_extension(cert, ef)
         
     | 
| 
       114 
     | 
    
         
            -
                     
     | 
| 
       115 
     | 
    
         
            -
                      if @settings[:subject_alt_names].empty?
         
     | 
| 
       116 
     | 
    
         
            -
                        "DNS:puppet, DNS:#{@settings[:certname]}"
         
     | 
| 
       117 
     | 
    
         
            -
                      else
         
     | 
| 
       118 
     | 
    
         
            -
                        @settings[:subject_alt_names]
         
     | 
| 
       119 
     | 
    
         
            -
                      end
         
     | 
| 
       120 
     | 
    
         
            -
                    alt_names_ext = ef.create_extension("subjectAltName", sans, false)
         
     | 
| 
      
 153 
     | 
    
         
            +
                  def add_subject_alt_names_extension(alt_names, cert, ef)
         
     | 
| 
      
 154 
     | 
    
         
            +
                    alt_names_ext = ef.create_extension("subjectAltName", alt_names, false)
         
     | 
| 
       121 
155 
     | 
    
         
             
                    cert.add_extension(alt_names_ext)
         
     | 
| 
       122 
156 
     | 
    
         
             
                  end
         
     | 
| 
       123 
157 
     | 
    
         | 
| 
         @@ -216,6 +250,10 @@ module Puppetserver 
     | 
|
| 
       216 
250 
     | 
    
         | 
| 
       217 
251 
     | 
    
         
             
                    cert
         
     | 
| 
       218 
252 
     | 
    
         
             
                  end
         
     | 
| 
      
 253 
     | 
    
         
            +
             
     | 
| 
      
 254 
     | 
    
         
            +
                  def update_serial_file(serial)
         
     | 
| 
      
 255 
     | 
    
         
            +
                    Puppetserver::Ca::Utils::FileSystem.write_file(@settings[:serial], serial, 0644)
         
     | 
| 
      
 256 
     | 
    
         
            +
                  end
         
     | 
| 
       219 
257 
     | 
    
         
             
                end
         
     | 
| 
       220 
258 
     | 
    
         
             
              end
         
     | 
| 
       221 
259 
     | 
    
         
             
            end
         
     | 
| 
         @@ -3,10 +3,22 @@ module Puppetserver 
     | 
|
| 
       3 
3 
     | 
    
         
             
                module Utils
         
     | 
| 
       4 
4 
     | 
    
         
             
                  module Config
         
     | 
| 
       5 
5 
     | 
    
         | 
| 
       6 
     | 
    
         
            -
                    def running_as_root?
         
     | 
| 
      
 6 
     | 
    
         
            +
                    def self.running_as_root?
         
     | 
| 
       7 
7 
     | 
    
         
             
                      !Gem.win_platform? && Process::UID.eid == 0
         
     | 
| 
       8 
8 
     | 
    
         
             
                    end
         
     | 
| 
       9 
9 
     | 
    
         | 
| 
      
 10 
     | 
    
         
            +
                    def self.munge_alt_names(names)
         
     | 
| 
      
 11 
     | 
    
         
            +
                      raw_names = names.split(/\s*,\s*/).map(&:strip)
         
     | 
| 
      
 12 
     | 
    
         
            +
                      munged_names = raw_names.map do |name|
         
     | 
| 
      
 13 
     | 
    
         
            +
                        # Prepend the DNS tag if no tag was specified
         
     | 
| 
      
 14 
     | 
    
         
            +
                        if !name.start_with?("IP:") && !name.start_with?("DNS:")
         
     | 
| 
      
 15 
     | 
    
         
            +
                          "DNS:#{name}"
         
     | 
| 
      
 16 
     | 
    
         
            +
                        else
         
     | 
| 
      
 17 
     | 
    
         
            +
                          name
         
     | 
| 
      
 18 
     | 
    
         
            +
                        end
         
     | 
| 
      
 19 
     | 
    
         
            +
                      end.sort.uniq.join(", ")
         
     | 
| 
      
 20 
     | 
    
         
            +
                    end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
       10 
22 
     | 
    
         
             
                  end
         
     | 
| 
       11 
23 
     | 
    
         
             
                end
         
     | 
| 
       12 
24 
     | 
    
         
             
              end
         
     | 
    
        metadata
    CHANGED
    
    | 
         @@ -1,14 +1,14 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            --- !ruby/object:Gem::Specification
         
     | 
| 
       2 
2 
     | 
    
         
             
            name: puppetserver-ca
         
     | 
| 
       3 
3 
     | 
    
         
             
            version: !ruby/object:Gem::Version
         
     | 
| 
       4 
     | 
    
         
            -
              version: 1. 
     | 
| 
      
 4 
     | 
    
         
            +
              version: 1.1.0
         
     | 
| 
       5 
5 
     | 
    
         
             
            platform: ruby
         
     | 
| 
       6 
6 
     | 
    
         
             
            authors:
         
     | 
| 
       7 
7 
     | 
    
         
             
            - Puppet, Inc.
         
     | 
| 
       8 
8 
     | 
    
         
             
            autorequire: 
         
     | 
| 
       9 
9 
     | 
    
         
             
            bindir: bin
         
     | 
| 
       10 
10 
     | 
    
         
             
            cert_chain: []
         
     | 
| 
       11 
     | 
    
         
            -
            date: 2018-09- 
     | 
| 
      
 11 
     | 
    
         
            +
            date: 2018-09-26 00:00:00.000000000 Z
         
     | 
| 
       12 
12 
     | 
    
         
             
            dependencies:
         
     | 
| 
       13 
13 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       14 
14 
     | 
    
         
             
              name: facter
         
     |