GithubHelp home page GithubHelp logo

danieldreier / autosign Goto Github PK

View Code? Open in Web Editor NEW
48.0 7.0 15.0 192 KB

Tooling to make puppet autosigning easy, secure, and extensible

Home Page: http://danieldreier.github.io/autosign/

License: Apache License 2.0

Ruby 93.65% Gherkin 6.35%

autosign's Introduction

autosign

Build Status Code Climate Dependency Status Yard Docs Inline docs Coverage Status Gem Version

Tooling to make puppet autosigning easy, secure, and extensible

Introduction

This tool provides a CLI for performing puppet policy-based autosigning using JWT tokens. Read more at https://danieldreier.github.io/autosign.

Quick Start: How to Generate Tokens

1. Install Gem on Puppet Master
gem install autosign
2. Generate default configuration
autosign config setup
3. Generate your first autosign token on the puppet master
autosign generate foo.example.com

The output will look something like

Autosign token for: foo.example.com, valid until: 2015-07-16 16:25:50 -0700
To use the token, put the following in ${puppet_confdir}/csr_attributes.yaml prior to running puppet agent for the first time:

custom_attributes:
  challengePassword: "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJkYXRhIjoie1wiY2VydG5hbWVcIjpcImZvby5leGFtcGxlLmNvbVwiLFwicmVxdWVzdGVyXCI6XCJEYW5pZWxzLU1hY0Jvb2stUHJvLTIubG9jYWxcIixcInJldXNhYmxlXCI6ZmFsc2UsXCJ2YWxpZGZvclwiOjcyMDAsXCJ1dWlkXCI6XCJkM2YyNzI0OC1jZDFmLTRhZmItYjI0MC02ZjBjMDU4NWJiZDNcIn0iLCJleHAiOiIxNDM3MDg5MTUwIn0.lC-EzWaV2dL81aLL7P-9mGwNbiOQDJWcoYjuSHVOqmaLtc7Wis5OZvHFOLln2Fn9qv98oSTnZsIkjmFpbI5dvA"

The resulting output can be copied to /etc/puppet/csr_attributes.yaml on an agent machine prior to running puppet for the first time to add the token to the CSR as the challengePassword OID. (just copy-paste from one terminal to another to copy the text)

Quick Start: Puppet Master Configuration

Run through the previous quick start steps to get the gem installed, then configure puppet to use the autosign-validator executable as the policy autosign command:

1. Prerequisities

Note that these settings will be slightly different if you're running Puppet Enterprise, because you'll need to use the pe-puppet user instead of puppet.

mkdir /var/autosign
chown puppet:puppet /var/autosign
chmod 750 /var/autosign
touch /var/log/autosign.log
chown puppet:puppet /var/log/autosign.log
2. Configure master
puppet config set autosign $(which autosign-validator) --section master

Your master is now configured to autosign using the autosign gem.

3. Using Legacy Autosign Scripts

If you already had an autosign script you want to continue using, add a setting to your autosign.conf like:

multiplexer:
  external_policy_executable: "/path/to/autosign/executable"

The master will validate the certificate if either the token validator or the external validator succeeds.

If the autosign script was just validating simple strings, you can use the password_list validator instead. For example, to configure the master to sign any CSR that includes the challenge passwords of "hunter2" or "CPE1704TKS" you would add:

password_list:
  password: "hunter2"
  password: "CPE1704TKS"

Note that this is a relatively insecure way to do certificate autosigning. Using one-time tokens via the autosign generate command is more secure. This functionality is provided to grandfather in existing use cases to ease the transition.

Validation order

By default the validation runs the following validators in order:

  1. jwt_token
  2. password_list
  3. multiplexer

The first validator to succeed wins and short circuits the validaiton process.

You can completely customize the list and how they are ordered via the configuration file. Or even remove some entirely.

---
general:
  loglevel: debug
  logfile: "/var/log/autosign.log"
  validation_order: 
    - jwt_token
    - multiplexer
    - password_list
jwt_token:
  secret: J7/WjmkC/CJp2K0/8+sktzSgCqQ=
  validity: '7200'
  journalfile: "/root/var/autosign/autosign.journal"

The validation_order config is an ordered array and since the validators will only match the first validation to succeed the validation script should occur as fast as you want.

Additionally, if you omit any validator that validator will not be used during the validation process. This might be important if you wanted to only use special validators or remove unwanted validator execution.

Please note, the name of the validator which is speficed by the NAME constant in the validator code must match the list you specify otherwise it will not be part of the validation process.

NOTE To use this feature you must have deep_merge 1.2.1+ installed which is now a requirement of this gem.

Troubleshooting

If you're having problems, try the following:

  • Set loglevel: "debug" in /etc/autosign.conf
  • Check the journalfile, in /var/autosign/autosign.journal by default, to see if the one-time token's UUID has already been recorded. It's just YAML, so you can either delete it or remove the offending entry if you actually want to re-use a token.
  • you can manually trigger the autosigning script with something like cat the_csr.csr | autosign-validator certname.example.com
  • If you run the puppet master foregrounded, you'll see quite a bit of autosign script output if autosign loglevel is set to debug.

Starting with the 1.0.0 release the autosign gem requires ruby 2.4. If you can't upgrade just yet you can continue to use the older 0.1.4 release.

Further Reading

autosign's People

Contributors

danieldreier avatar danielparks avatar dependabot[bot] avatar hanikesn avatar justinstoller avatar logicminds avatar matikij avatar mikkergimenez avatar reidmv avatar rpearce-wmpromus avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

autosign's Issues

Add trusted facts CLI tooling

In order to facilitate requiring specific trusted facts, we should add CLI tooling that makes it easier to add trusted facts to csr_attributes.yaml.

We should read the trusted fact - OID mapping file on the master in order to allow people to specify facts by name rather than OID.

fail gracefully with exit 1 when multiplexer script does not exist

[root@pe-xl-core-0 /]# cat test.pem | autosign-validator foo2.example.org
 INFO  Autosign::Validators::JWT : validated settings successfully
 INFO  Autosign::Validators::JWT : attempting to validate JWT token
 INFO  Autosign::Validators::JWT : validated settings successfully
 WARN  Autosign::Validators::Passwordlist : Unable to load validator-specific configuration
 WARN  Autosign::Validators::Passwordlist : Cannot load configuration section named 'password_list'
 WARN  Autosign::Validators::Passwordlist : Unable to load validator-specific configuration
 WARN  Autosign::Validators::Passwordlist : Cannot load configuration section named 'password_list'
 WARN  Autosign::Validators::Passwordlist : Unable to load validator-specific configuration
 WARN  Autosign::Validators::Passwordlist : Cannot load configuration section named 'password_list'
Traceback (most recent call last):
	11: from /opt/puppetlabs/puppet/bin/autosign-validator:23:in `<main>'
	10: from /opt/puppetlabs/puppet/bin/autosign-validator:23:in `load'
	 9: from /opt/puppetlabs/puppet/lib/ruby/gems/2.5.0/gems/autosign-0.1.4/bin/autosign-validator:44:in `<top (required)>'
	 8: from /opt/puppetlabs/puppet/lib/ruby/gems/2.5.0/gems/autosign-0.1.4/lib/autosign/validator.rb:34:in `any_validator'
	 7: from /opt/puppetlabs/puppet/lib/ruby/gems/2.5.0/gems/autosign-0.1.4/lib/autosign/validator.rb:34:in `find'
	 6: from /opt/puppetlabs/puppet/lib/ruby/gems/2.5.0/gems/autosign-0.1.4/lib/autosign/validator.rb:34:in `each'
	 5: from /opt/puppetlabs/puppet/lib/ruby/gems/2.5.0/gems/autosign-0.1.4/lib/autosign/validator.rb:34:in `block in any_validator'
	 4: from /opt/puppetlabs/puppet/lib/ruby/gems/2.5.0/gems/autosign-0.1.4/lib/autosign/validators/validator_base.rb:60:in `validate'
	 3: from /opt/puppetlabs/puppet/lib/ruby/gems/2.5.0/gems/autosign-0.1.4/lib/autosign/validators/multiplexer.rb:43:in `perform_validation'
	 2: from /opt/puppetlabs/puppet/lib/ruby/gems/2.5.0/gems/autosign-0.1.4/lib/autosign/validators/multiplexer.rb:43:in `each'
	 1: from /opt/puppetlabs/puppet/lib/ruby/gems/2.5.0/gems/autosign-0.1.4/lib/autosign/validators/multiplexer.rb:45:in `block in perform_validation'
/opt/puppetlabs/puppet/lib/ruby/gems/2.5.0/gems/autosign-0.1.4/lib/autosign/validators/multiplexer.rb:45:in `popen': No such file or directory - /etc/legacy_autosign/autosign.py (Errno::ENOENT)

Unable to utilize token for CSR

I am able to create an autosign token and then place the custom attributes information under the etc/puppetlabs/puppet directory in the agent. However, once I run puppet agent -t on the agent it does not register the token and requests a manual certificate signing request. To give some background, I am running this on Linux servers with Puppet Enterprise 2019.2.

autosign.log logging debug level even though .conf has loglevel: warn

puppet:/var/log # cat /etc/autosign.conf

general:
loglevel: warn
logfile: /var/log/autosign.log

puppet:/var/log # cat autosign.log
DEBUG Autosign : certname is ##########.example.com
DEBUG Autosign : reading CSR from stdin
DEBUG Autosign::Decoder : decoding CSR
INFO Autosign::Decoder : Decoded CSR for CN: ##########.example.com
DEBUG Autosign::Decoder : Decoded CSR as:

---cut for brevity---

DEBUG Autosign::Validator::multiplexer : starting autosign validator: multiplexer
DEBUG Autosign::Validator::multiplexer : merging settings
DEBUG Autosign::Validator::multiplexer : loading validator-specific configuration
DEBUG Autosign::Config : initializing Autosign::Config
DEBUG Autosign::Config : Using merged settings hash: {}
DEBUG Autosign::Config : merging settings
DEBUG Autosign::Config : Finding config file
DEBUG Autosign::Config : Checking if file '/etc/autosign.conf' exists
DEBUG Autosign::Config : Reading config file from: /etc/autosign.conf

tokens should allow custom metadata

When I generate a wildcard token I would like to include custom data so I can track it in the autosign journal, for example to associate a puppet config version number, hostname that was expected to use the cert, etc.

Multiplexer command always has exit code 0

I am implementing autosign 1.0.1 using puppet-autosign HEAD@4c57cdd5bb86fb935fd4d82d14a4ab3409327779 with Puppet 7.29.1 and ruby 2.7.8, and I've configured the validator to fallback to a custom policy executable with the following in /etc/autosign.conf

multiplexer:
  external_policy_executable: "/etc/puppetlabs/puppet/autosign-policy"

The policy executable is just a stub for now and I want it to reject everything, so I have it like this:

#!/bin/bash
exit 1

However, when the validator runs this command, it always returns 0, and the cert gets signed. To rule out problems with the script, I changed the external_policy_executable to /bin/false, which produces this unbelievable result in the autosign debug log:

2024-04-09T14:57:35.955395 DEBUG -- Autosign::Validator::Multiplexer : starting autosign validator: multiplexer
2024-04-09T14:57:35.955436 DEBUG -- Autosign::Validator::Multiplexer : merging settings for multiplexer validator
2024-04-09T14:57:35.955483 DEBUG -- Autosign::Validator::Multiplexer : loading validator-specific configuration
2024-04-09T14:57:35.955529 DEBUG -- Autosign::Validator::Multiplexer : Set validator-specific settings from config file: {"external_policy_executable"=>"/bin/false"}
2024-04-09T14:57:35.955598 DEBUG -- Autosign::Validator::Multiplexer : using merged settings: {"external_policy_executable"=>"/bin/false", "strategy"=>"any"}
2024-04-09T14:57:35.955634 DEBUG -- Autosign::Validator::Multiplexer : validating merged settings
2024-04-09T14:57:35.955681 DEBUG -- Autosign::Validator::Multiplexer : validating settings: {"external_policy_executable"=>"/bin/false", "strategy"=>"any"}
2024-04-09T14:57:35.955734 DEBUG -- Autosign::Validator::Multiplexer : done validating settings
2024-04-09T14:57:35.955776 DEBUG -- Autosign::Validator::Multiplexer : successfully validated merged settings
2024-04-09T14:57:35.955819 DEBUG -- Autosign::Validator::Multiplexer : validating using multiplexed external executables
2024-04-09T14:57:35.955862 DEBUG -- Autosign::Validator::Multiplexer : attempting to validate using /bin/false
2024-04-09T14:57:35.956793 DEBUG -- Autosign::Validator::Multiplexer : exit code from /bin/false: 0
2024-04-09T14:57:35.956845 DEBUG -- Autosign::Validator::Multiplexer : validating using 'any' strategy
2024-04-09T14:57:35.956895 DEBUG -- Autosign::Validator::Multiplexer : validated successfully

How can /bin/false exit with code 0?

root@puppet1:~# /bin/false
root@puppet1:~# echo $?
1
root@puppet1:~# lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 22.04.4 LTS
Release:        22.04
Codename:       jammy

Add policy file support

based on feedback at the contributor summit, there would be interest in having way to specify policy logic composed of multiple validators.

# example policy file format
# module                  condition             parameters
trusted_facts             required              fqdn, domain, role
jwt                       sufficient
apikey                    sufficient

Detection of regex matching certnames seems wrong

Detecting if a token has a regex certname matcher is handled at lib/autosign/token.rb line 80:

certname_is_regex = (data["certname"] =~ /\/[^\/].*\//) ? true : false
. . .
regexp = Regexp.new(/\/([^\/].*)\//.match(data["certname"])[1])

Test code:

def check ( s )
  formatted = s.gsub(/\n/, " **\\n** ")
  if s =~ /\/([^\/].*)\//
    result = $1.gsub(/\n/, " **\\n** ")
    puts "#{formatted} | :white_check_mark: | #{result}"
  else
    puts "#{formatted} | :x: |"
  end
end

Results (newlines appear as " \n "):

token certname is regex? regex detected
hello
/blah
//blah
///hey/ hey
a/b/c b
/test/ test\
foo/ \n that was a newline/ \n that was a newline
newline: \n /abc/ \n last abc
/ \n newlines \n /

You could probably just Regexp.escape when generating the token, and then unconditionally use a regex.

Or, if you never care about literal certnames starting and ending with a /, use the regex /\A\/(.+)\/\Z/:

token certname is regex? regex detected
hello
/blah
//blah
///hey/ //hey
a/b/c
/test/ test\
foo/ \n that was a newline/
newline: \n /abc/ \n last
/ \n newlines \n /

Why \A? /^\/(.+)\/$/:

token certname is regex? regex detected
hello
/blah
//blah
///hey/ //hey
a/b/c
/test/ test\
foo/ \n that was a newline/
newline: \n /abc/ \n last abc
/ \n newlines \n /

If you want to allow newlines, use /\A\/(.+)\/\Z/m:

token certname is regex? regex detected
hello
/blah
//blah
///hey/ //hey
a/b/c
/test/ test\
foo/ \n that was a newline/
newline: \n /abc/ \n last
/ \n newlines \n / \n newlines \n

can't find gem autosign (>= 0.a) with executable autosign-validator

2022-08-19T17:14:34.284+03:00 WARN [qtp1979408284-60] [c.p.p.ShellUtils] Executed an external process which logged to STDERR: /usr/share/rubygems/rubygems.rb:284:in find_spec_for_exe': can't find gem autosign (>= 0.a) with executable autosign-validator (Gem::GemNotFoundException) from /usr/share/rubygems/rubygems.rb:303:in activate_bin_path'
from /usr/local/bin/autosign-validator:23:in `

'

2022-08-19T17:14:34.286+03:00 WARN [qtp1979408284-60] [p.p.certificate-authority] Autosign command '/usr/local/bin/autosign-validator mydomain.puppet' generated output to stderr: /usr/share/rubygems/rubygems.rb:284:in find_spec_for_exe': can't find gem autosign (>= 0.a) with executable autosign-validator (Gem::GemNotFoundException) from /usr/share/rubygems/rubygems.rb:303:in activate_bin_path'
from /usr/local/bin/autosign-validator:23:in `

'

2022-08-19T17:14:34.287+03:00 WARN [qtp1979408284-60] [p.p.certificate-authority] Autosign command '/usr/local/bin/autosign-validator' rejected certificate 'mydomain.puppet' because the exit code was 1, not zero

config is created multiple times

During validation I noticed that the config is created / read multiple times (for each validator) when it should be a more global or inherited object.

To fix we need to put the config at a base level and either pass it in or reference it.

logging seems to be broken in subclasses - cretates Autosign::Config and Autosign::Token files in cwd

Hi, it seems that whenever I use autosign binary or the puppet function there are some files created in current directory. The files are named "Autosign::Config" and "Autosign::Token". After some investigation it turns out that (at least in logging gem version 2.1 ) when

Logging.logger('Autosign::Config', {:date_pattern => '%Y-%m-%dT%H:%M:%S.%s'})

is executed the logging gem treats the first arument as a filename and tries to create it.

Token not saved in journal file

Hi, I am trying to use autosign but for some reason I keep getting the Unable to validate token error. Upon checking the journal file it seems the token isn't saved. I installed autosign via the puppet-autosign module.

My configuration looks like this:

---
general:
  loglevel: DEBUG
  logfile: "/var/log/autosign.log"
jwt_token:
  validity: '31556926'
  journalfile: "/var/lib/autosign/autosign.journal"
  secret: suppersecretpassword

When I generate the token:

/opt/puppetlabs/puppet/bin/autosign --debug --config=/etc/autosign.conf generate -r -t 31556926 *.example.com
DEBUG -- Autosign::Config : initializing Autosign::Config
DEBUG -- Autosign::Config : Using merged settings hash: {"config_file"=>"/etc/autosign.conf"}
DEBUG -- Autosign::Config : merging settings
DEBUG -- Autosign::Config : Finding config file
DEBUG -- Autosign::Config : Checking if file '/etc/autosign.conf' exists
DEBUG -- Autosign::Config : Reading config file from: /etc/autosign.conf
DEBUG -- Autosign::Config : configuration read from config file: {"general"=>{"loglevel"=>"DEBUG", "logfile"=>"/var/log/autosign.log"}, "jwt_token"=>{"validity"=>"31556926", "journalfile"=>"/var/lib/autosign/autosign.journal", "secret"=>"suppersecretpassword"}}
DEBUG -- Autosign::Config : using merged settings: {"general"=>{"loglevel"=>"DEBUG", "logfile"=>"/var/log/autosign.log"}, "jwt_token"=>{"validity"=>"31556926", "journalfile"=>"/var/lib/autosign/autosign.journal", "secret"=>"suppersecretpassword"}, "config_file"=>"/etc/autosign.conf"}
DEBUG -- Autosign : validfor: 31556926
DEBUG -- Autosign::Token : initializing Autosign::Token
INFO  -- Autosign : generated token for: *.example.com
Autosign token for: *.example.com, valid until: 2019-04-12 18:10:24 +0000
To use the token, put the following in ${puppet_confdir}/csr_attributes.yaml prior to running puppet agent for the first time:

custom_attributes:
  challengePassword: "ey.....sAte4yBFyQ"

But when I check the journal (/var/lib/autosign/autosign.journal) it's empty. Am I doing something wrong?

Possible to put instructions in stderr and custom attributes in stdout?

We'd like to be able to have the instructions that are generated when running autosign to generate a token redirected to stderr and the token info itself sent to stdout so we don't have to parse the instructions out. (we're lazy)

Context: Automate generation of token without having to parse instructions out of returned string.

cucumber test fails when autosign.conf file exist

Feature: Validate autosign key
  In order to sign puppet certificates automatically
  I want to validate autosign keys programatically
  So that I only grant access to allowed systems without needing manual authorization

  Scenario: Validate a certificate signing request                # features/validate.feature:6
    Given I set the environment variables to:                     # aruba-0.14.14/lib/aruba/cucumber/environment.rb:17
      | variable                  | value                 |
      | AUTOSIGN_TESTMODE         | true                  |
      | AUTOSIGN_TEST_SECRET      | secret                |
      | AUTOSIGN_TEST_LOGLEVEL    | info                  |
      | AUTOSIGN_TEST_JOURNALFILE | /tmp/autosign_journal |
    When I run `rm -f /tmp/autosign_journal`                      # aruba-0.14.14/lib/aruba/cucumber/command.rb:6
    And I run `autosign-validator i-7672fe81` interactively       # aruba-0.14.14/lib/aruba/cucumber/command.rb:29
    And I pipe in the file "../../fixtures/i-7672fe81.pem"        # aruba-0.14.14/lib/aruba/cucumber/command.rb:47
    Then the output should contain "token validated successfully" # aruba-0.14.14/lib/aruba/cucumber/command.rb:139
      expected "" to string includes: "token validated successfully" (RSpec::Expectations::ExpectationNotMetError)
      features/validate.feature:16:in `Then the output should contain "token validated successfully"'
    Then the exit status should be 0                

Removing any autosign.conf file will fix this test.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.