Class: MCollective::Signer::Choria
- Defined in:
- lib/mcollective/signer/choria.rb
Overview
This is a Secure Request Signer that allows either local signing of requests using the users own certificate or delegation based signing via a webservice
This allows one to integrate the Choria CLI into a centralised authentication, authorization and auditing system
Available settings:
choria.security.request_signer.plugin - the plugin to use, `choria` for this one - the default.
choria.security.request_signer.token_file - a file holding a token like a JWT or similar
choria.security.request_signer.token_environment - a ENV key holding a token like a JWT or similar
choria.security.request_signer.url - a endpoint that implements the v1 signer protocol
The webservice has to support the specification found at choria.io/schemas/choria/signer/v1/service.json
Instance Method Summary collapse
-
#callerid ⇒ String
Determines the callerid for this client.
- #choria ⇒ Object
-
#client_public_cert ⇒ String
The path to a client public certificate.
-
#local_sign!(secure_request) ⇒ Object
Signs using local certificates.
-
#remote_sign!(secure_request) ⇒ Object
Performs a remote sign operation against a configured web service.
-
#remote_signer? ⇒ Boolean
Determines if a remote signer is configured.
-
#remote_signer_url ⇒ URI, Nil
Determines the remote url to submit standard signing requests to.
- #security ⇒ Object
-
#sign(string, id = nil) ⇒ String
Signs a string using the private key.
-
#sign_request_body(secure_request) ⇒ Hash
The body that would be submitted to the remote service.
-
#sign_secure_request!(secure_request) ⇒ Object
Signs the secure request.
-
#token ⇒ String?
Retrieves the token from either a local file or the users environment.
Methods inherited from Base
Constructor Details
This class inherits a constructor from MCollective::Signer::Base
Instance Method Details
#callerid ⇒ String
Determines the callerid for this client
When a remote signer is enabled the caller is extracted from the JWT otherwise a choria=user style ID is generated
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
# File 'lib/mcollective/signer/choria.rb', line 63 def callerid if remote_signer? parts = token.split(".") raise("Invalid JWT token") unless parts.length == 3 claims = JSON.parse(Base64.decode64(parts[1])) raise("Invalid JWT token") unless claims.include?("callerid") raise("Invalid JWT token") unless claims["callerid"].is_a?(String) raise("Invalid JWT token") if claims["callerid"].empty? claims["callerid"] else "choria=%s" % choria.certname end end |
#choria ⇒ Object
180 181 182 |
# File 'lib/mcollective/signer/choria.rb', line 180 def choria @choria ||= security.choria end |
#client_public_cert ⇒ String
paths determined by Puppet AIO packages
The path to a client public certificate
155 156 157 |
# File 'lib/mcollective/signer/choria.rb', line 155 def client_public_cert security.client_public_cert end |
#local_sign!(secure_request) ⇒ Object
Signs using local certificates
140 141 142 143 144 145 146 147 |
# File 'lib/mcollective/signer/choria.rb', line 140 def local_sign!(secure_request) Log.info("Signing secure request using local credentials") secure_request["signature"] = sign(secure_request["message"]) secure_request["pubcert"] = File.read(client_public_cert).chomp nil end |
#remote_sign!(secure_request) ⇒ Object
Performs a remote sign operation against a configured web service
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
# File 'lib/mcollective/signer/choria.rb', line 96 def remote_sign!(secure_request) Log.info("Signing secure request using remote signer %s" % remote_signer_url) uri = remote_signer_url post = choria.http_post(uri.request_uri) post.body = sign_request_body(secure_request).to_json post["Content-type"] = "application/json" http = choria.https(:target => uri.host, :port => uri.port) http.use_ssl = false if uri.scheme == "http" # While this might appear alarming it's expected that the clients # in this situation will not have any Choria CA issued certificates # and so wish to use a remote signer - the certificate management woes # being one of the main reasons for centralised AAA. # # So there is no realistic way to verify these requests especially in the # event that these signers run on private IPs and such as would be typical # so while we do this big No No of disabling verify here it really is the # only thing that make sense. http.verify_mode = OpenSSL::SSL::VERIFY_NONE if http.use_ssl? resp = http.request(post) signature = {} if resp.code == "200" signature = JSON.parse(resp.body) else raise("Could not get remote signature: %s: %s" % [resp.code, resp.body]) end raise("Could not get remote signature: %s" % signature["error"]) if signature["error"] signed_request = JSON.parse(Base64.decode64(signature["secure_request"])) signed_request.each do |k, v| secure_request[k] = v end end |
#remote_signer? ⇒ Boolean
Determines if a remote signer is configured
162 163 164 |
# File 'lib/mcollective/signer/choria.rb', line 162 def remote_signer? !!(remote_signer_url == "" || remote_signer_url) end |
#remote_signer_url ⇒ URI, Nil
Determines the remote url to submit standard signing requests to
169 170 171 172 173 174 |
# File 'lib/mcollective/signer/choria.rb', line 169 def remote_signer_url return nil unless @config.pluginconf["choria.security.request_signer.url"] return nil if @config.pluginconf["choria.security.request_signer.url"] == "" URI.parse(@config.pluginconf["choria.security.request_signer.url"]) end |
#security ⇒ Object
176 177 178 |
# File 'lib/mcollective/signer/choria.rb', line 176 def security @security ||= PluginManager["security_plugin"] end |
#sign(string, id = nil) ⇒ String
Signs a string using the private key
150 151 152 |
# File 'lib/mcollective/signer/choria.rb', line 150 def sign(string, id=nil) security.sign(string, id) end |
#sign_request_body(secure_request) ⇒ Hash
The body that would be submitted to the remote service
85 86 87 88 89 90 |
# File 'lib/mcollective/signer/choria.rb', line 85 def sign_request_body(secure_request) { "token" => token, "request" => Base64.encode64(secure_request["message"]) } end |
#sign_secure_request!(secure_request) ⇒ Object
Signs the secure request
Signing supports either local mode using local certificates or delegating to a remote signer that is written in conformance with the signer specification version 1
46 47 48 49 50 51 52 53 54 |
# File 'lib/mcollective/signer/choria.rb', line 46 def sign_secure_request!(secure_request) return if $choria_unsafe_disable_protocol_security # rubocop:disable Style/GlobalVars if remote_signer? remote_sign!(secure_request) else local_sign!(secure_request) end end |
#token ⇒ String?
Retrieves the token from either a local file or the users environment
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
# File 'lib/mcollective/signer/choria.rb', line 23 def token file = @config.pluginconf["choria.security.request_signer.token_file"] env = @config.pluginconf["choria.security.request_signer.token_environment"] if file file = File.(file) raise("No token found in %s, please authenticate using your configured authentication service" % file) unless File.exist?(file) return File.read(file).chomp end raise("could not find token in environment variable %s" % env) unless ENV[env] ENV[env].chomp end |