Module: HybridPlatformsConductor::Credentials
- Included in:
- Bitbucket, Confluence, Github, HpcPlugins::Provisioner::Proxmox, HpcPlugins::SecretsReader::Keepass, HpcPlugins::Test::JenkinsCiConf, HpcPlugins::Test::JenkinsCiMastersOk, Thycotic
- Defined in:
- lib/hybrid_platforms_conductor/credentials.rb
Overview
Give a secured and harmonized way to access credentials for a given service. It makes sure to remove passwords from memory for hardened security (this way if a vulnerability allows an attacker to dump the memory it won’t get passwords). It gets credentials from the following sources:
-
Configuration
-
Environment variables
-
Netrc file
Defined Under Namespace
Modules: ConfigDSLExtension
Instance Method Summary collapse
-
#with_credentials_for(id, resource: nil) ⇒ Object
Get access to credentials and make sure they are wiped out from memory when client code ends.
Instance Method Details
#with_credentials_for(id, resource: nil) ⇒ Object
Get access to credentials and make sure they are wiped out from memory when client code ends. To ensure password safety, never store the password in a scope beyond the client code’s Proc.
- Parameters
-
id (Symbol): Credential ID
-
resource (String or nil): The resource for which we want the credentials, or nil if not associated to a resource [default: nil]
-
Proc: Client code called with credentials provided
- Parameters
-
user (String or nil): User name, or nil if none
-
password (SecretString or nil): Password, or nil if none. !!! Never clone this password in a scope broader than the client code itself !!!
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 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 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 |
# File 'lib/hybrid_platforms_conductor/credentials.rb', line 71 def with_credentials_for(id, resource: nil) # Get the credentials provider provider = nil # Check configuration # Take the last matching provider, this way we can define several providers for resources matched in a increasingly refined way. @config.credentials.each do |credentials_info| provider = credentials_info[:provider] if credentials_info[:credential_id] == id && ( (resource.nil? && credentials_info[:resource] == /.*/) || credentials_info[:resource] =~ resource ) end provider ||= proc do |requested_resource, requester| # Check environment variables user = ENV["hpc_user_for_#{id}"] # Clone the password as we are going to treat it as a secret string that will be wiped out password = ENV["hpc_password_for_#{id}"].dup if user.nil? || user.empty? || password.nil? || password.empty? log_debug "[ Credentials for #{id} ] - Credentials not found from environment variables." if requested_resource.nil? log_debug "[ Credentials for #{id} ] - No resource associated to this credentials, so .netrc can't be used." else # Check Netrc netrc = ::Netrc.read begin netrc_user, netrc_password = netrc[ begin URI.parse(requested_resource).host.downcase rescue URI::InvalidURIError requested_resource end ] if netrc_user.nil? log_debug "[ Credentials for #{id} ] - No credentials retrieved from .netrc." # TODO: Add more credentials source if needed here log_warn "[ Credentials for #{id} ] - Unable to get credentials for #{id} (Resource: #{requested_resource})." else # Clone in memory as we are going to wipe out ::Netrc's memory user = netrc_user.dup password = netrc_password.dup log_debug "[ Credentials for #{id} ] - Credentials retrieved from .netrc using #{requested_resource}." end ensure # Make sure the password does not stay in Netrc memory # Wipe out any memory trace that might contain passwords in clear netrc.instance_variable_get(:@data).each do |data_line| data_line.each do |data_string| data_string.replace('GotYou!!!' * 100) end end end end else log_debug "[ Credentials for #{id} ] - Credentials retrieved from environment variables." end if password.nil? requester.call user, password else SecretString.protect(password) do |secret_password| requester.call user, secret_password end end end requester_called = false provider.call( resource, proc do |user, password| requester_called = true if password.is_a?(String) SecretString.protect(password) do |secret_password| yield user, secret_password end else yield user, password end end ) raise "Requester not called by the credentials provider for #{id} (resource: #{resource}) - Please check the credentials_for code in your configuration." unless requester_called end |