Class: Conjur::API
- Inherits:
-
Object
- Object
- Conjur::API
- Includes:
- BuildObject, Escape, LogSource
- Defined in:
- lib/conjur/base.rb,
lib/conjur/api/authn.rb,
lib/conjur/api/roles.rb,
lib/conjur-api/version.rb,
lib/conjur/api/pubkeys.rb,
lib/conjur/api/policies.rb,
lib/conjur/api/resources.rb,
lib/conjur/api/variables.rb,
lib/conjur/api/host_factories.rb
Overview
This class provides access to the Conjur services.
Defined Under Namespace
Modules: MonotonicTime, TokenExpiration Classes: APIKeyAuthenticator, TokenFileAuthenticator, UnableAuthenticator
Policy management collapse
- POLICY_METHOD_POST =
Append only.
:post
- POLICY_METHOD_PATCH =
Allow explicit deletion statements, but don't delete implicitly delete data.
:patch
- POLICY_METHOD_PUT =
Replace the policy entirely, deleting any existing data that is not declared in the new policy.
:put
Constant Summary collapse
- VERSION =
"5.0.0"
Instance Attribute Summary collapse
-
#api_key ⇒ String
readonly
The api key used to create this instance.
-
#authenticator ⇒ Object
readonly
Returns the value of attribute authenticator.
-
#remote_ip ⇒ Object
readonly
An optional IP address to be recorded in the audit record for any actions performed by this API instance.
Authentication collapse
-
.authenticate(username, api_key, account: Conjur.configuration.account) ⇒ String
Exchanges Conjur the API key (refresh token) for an access token.
-
.login(username, password, account: Conjur.configuration.account) ⇒ String
Exchanges a username and a password for an api key.
-
.update_password(username, password, new_password, account: Conjur.configuration.account)
Change a user's password.
Password and API key management collapse
-
.rotate_api_key(username, password, account: Conjur.configuration.account) ⇒ String
Rotate the currently authenticated user or host API key by generating and returning a new one.
Roles collapse
-
#current_role(account) ⇒ Conjur::Role
Return a Role object representing the role (typically a user or host) that this API instance is authenticated as.
-
#role(id) ⇒ Conjur::Role
Return a Role representing a role with the given id.
Public Keys collapse
-
.public_keys(username, account: Conjur.configuration.account) ⇒ String
Fetch all public keys for the user.
Policy management collapse
-
#load_policy(id, policy, account: Conjur.configuration.account, method: POLICY_METHOD_POST) ⇒ Object
Load a policy document into the server.
Resources collapse
-
#resource(id) ⇒ Conjur::Resource
Find a resource by it's id.
-
#resources(options = {}) ⇒ Array<Conjur::Resource>
Find all resources visible to the current role that match the given search criteria.
Variables collapse
-
#variable_values(variable_ids) ⇒ Array<String>
Fetch the values of a list of variables.
Class Method Summary collapse
-
.host_factory_create_host(token, id, options = {}) ⇒ Host
Use a host factory token to create a new host.
-
.new_from_key(username, api_key, remote_ip: nil, account: Conjur.configuration.account) ⇒ Conjur::API
Create a new API instance from a username and a password or api key.
-
.new_from_token(token, remote_ip: nil) ⇒ Conjur::API
Create a new API instance from an access token.
-
.new_from_token_file(token_file, remote_ip: nil) ⇒ Conjur::API
Create a new API instance from a file containing a token issued by the Conjur authentication service.
-
.revoke_host_factory_token(credentials, token) ⇒ Object
Revokes a host factory token.
Instance Method Summary collapse
-
#credentials ⇒ Hash
Credentials that can be merged with options to be passed to
RestClient::Resource
HTTP request methods. - #init_from_key(username, api_key, remote_ip: nil, account: Conjur.configuration.account) ⇒ Object
- #init_from_token(token, remote_ip: nil) ⇒ Object
- #init_from_token_file(token_file, remote_ip: nil) ⇒ Object
-
#revoke_host_factory_token(token) ⇒ Object
Revokes a host factory token.
-
#token ⇒ Hash
The token used to authenticate requests made with the api.
-
#username ⇒ String
The name of the user as which this api instance is authenticated.
Methods included from BuildObject
Methods included from LogSource
Methods included from Escape
#fully_escape, #path_escape, #query_escape
Instance Attribute Details
#api_key ⇒ String (readonly)
The api key used to create this instance. This is only present when you created the api with new_from_key.#
110 111 112 |
# File 'lib/conjur/base.rb', line 110 def api_key @api_key end |
#authenticator ⇒ Object (readonly)
Returns the value of attribute authenticator.
279 280 281 |
# File 'lib/conjur/base.rb', line 279 def authenticator @authenticator end |
#remote_ip ⇒ Object (readonly)
An optional IP address to be recorded in the audit record for any actions performed by this API instance.
114 115 116 |
# File 'lib/conjur/base.rb', line 114 def remote_ip @remote_ip end |
Class Method Details
.authenticate(username, api_key, account: Conjur.configuration.account) ⇒ String
Exchanges Conjur the API key (refresh token) for an access token. The access token can then be used to authenticate further API calls.
60 61 62 63 64 65 66 |
# File 'lib/conjur/api/authn.rb', line 60 def authenticate username, api_key, account: Conjur.configuration.account account ||= Conjur.configuration.account if Conjur.log Conjur.log << "Authenticating #{username} to account #{account}\n" end JSON::parse(RestClient::Resource.new(Conjur.configuration.authn_url)[fully_escape account][fully_escape username]['authenticate'].post api_key, content_type: 'text/plain') end |
.host_factory_create_host(token, id, options = {}) ⇒ Host
Use a host factory token to create a new host. Unlike most other methods, this method does not require a Conjur access token. The host factory token is the authentication and authorization to create the host.
The token must be valid. The host id can be a new host, or an existing host. If the host already exists, the server verifies that its layer memberships match the host factory exactly. Then, its API key is rotated and returned with the response.
41 42 43 44 45 46 47 48 49 50 51 |
# File 'lib/conjur/api/host_factories.rb', line 41 def host_factory_create_host token, id, = {} token = token.token if token.is_a?(HostFactoryToken) = { headers: { authorization: %Q(Token token="#{token}") } } response = RestClient::Resource.new(Conjur.configuration.core_url, )["host_factories"]["hosts"].post(.merge(id: id)).body attributes = JSON.parse(response) Host.new(attributes['id'], {}).tap do |host| host.attributes = attributes end end |
.login(username, password, account: Conjur.configuration.account) ⇒ String
Exchanges a username and a password for an api key. The api key is preferable for storage and use in code, as it can be rotated and has far greater entropy than a user memorizable password.
46 47 48 49 50 51 |
# File 'lib/conjur/api/authn.rb', line 46 def login username, password, account: Conjur.configuration.account if Conjur.log Conjur.log << "Logging in #{username} to account #{account} via Basic authentication\n" end RestClient::Resource.new(Conjur.configuration.authn_url, user: username, password: password)[fully_escape account]['login'].get end |
.new_from_key(username, api_key, remote_ip: nil, account: Conjur.configuration.account) ⇒ Conjur::API
Create a new Conjur::API instance from a username and a password or api key.
58 59 60 |
# File 'lib/conjur/base.rb', line 58 def new_from_key username, api_key, remote_ip: nil, account: Conjur.configuration.account self.new.init_from_key username, api_key, remote_ip: remote_ip, account: account end |
.new_from_token(token, remote_ip: nil) ⇒ Conjur::API
Create a new Conjur::API instance from an access token.
Generally, you will have a Conjur identitiy (username and API key), and create an Conjur::API instance for the identity using new_from_key. This method is useful when you are performing authorization checks given a token. For example, a Conjur gateway that requires you to prove that you can 'read' a resource named 'super-secret' might get the token from a request header, create an Conjur::API instance with this method, and use Resource#permitted? to decide whether to accept and forward the request.
86 87 88 |
# File 'lib/conjur/base.rb', line 86 def new_from_token token, remote_ip: nil self.new.init_from_token token, remote_ip: remote_ip end |
.new_from_token_file(token_file, remote_ip: nil) ⇒ Conjur::API
Create a new Conjur::API instance from a file containing a token issued by the Conjur authentication service. The file is read the first time that a token is required. It is also re-read whenever the API decides that the token it already has is getting close to expiration.
This method is useful when an external process, such as a sidecar container, is continuously obtaining fresh tokens and writing them to a known file.
101 102 103 |
# File 'lib/conjur/base.rb', line 101 def new_from_token_file token_file, remote_ip: nil self.new.init_from_token_file token_file, remote_ip: remote_ip end |
.public_keys(username, account: Conjur.configuration.account) ⇒ String
Fetch all public keys for the user. This method returns a newline delimited String for compatibility with the authorized_keys SSH format.
If the given user does not exist, an empty String will be returned. This is to prevent attackers from determining whether a user exists.
Permissions
You do not need any special permissions to call this method, since public keys are, well, public.
46 47 48 |
# File 'lib/conjur/api/pubkeys.rb', line 46 def public_keys username, account: Conjur.configuration.account public_keys_resource(username, account).get end |
.revoke_host_factory_token(credentials, token) ⇒ Object
Revokes a host factory token. After revocation, the token can no longer be used to create hosts.
58 59 60 |
# File 'lib/conjur/api/host_factories.rb', line 58 def revoke_host_factory_token credentials, token RestClient::Resource.new(Conjur.configuration.core_url, credentials)['host_factory_tokens'][token].delete end |
.rotate_api_key(username, password, account: Conjur.configuration.account) ⇒ String
Rotate the currently authenticated user or host API key by generating and returning a new one. The old API key is no longer valid after calling this method. You must have the current API key or password to perform this operation. This method does not affect a user's password.
96 97 98 99 100 101 102 103 104 105 106 |
# File 'lib/conjur/api/authn.rb', line 96 def rotate_api_key username, password, account: Conjur.configuration.account if Conjur.log Conjur.log << "Rotating API key for self (#{username} in account #{account})\n" end RestClient::Resource.new( Conjur.configuration.authn_url, user: username, password: password )[fully_escape account]['api_key'].put('').body end |
.update_password(username, password, new_password, account: Conjur.configuration.account)
This method returns an undefined value.
Change a user's password. To do this, you must have the user's current password. This does not change or rotate api keys. However, you can use the user's api key as the current password, if the user was not created with a password.
77 78 79 80 81 82 |
# File 'lib/conjur/api/authn.rb', line 77 def update_password username, password, new_password, account: Conjur.configuration.account if Conjur.log Conjur.log << "Updating password for #{username} in account #{account}\n" end RestClient::Resource.new(Conjur.configuration.authn_url, user: username, password: password)[fully_escape account]['password'].put new_password end |
Instance Method Details
#credentials ⇒ Hash
Credentials that can be merged with options to be passed to RestClient::Resource
HTTP request methods.
These include a username and an Authorization header containing the authentication token.
147 148 149 150 151 152 153 |
# File 'lib/conjur/base.rb', line 147 def credentials headers = {}.tap do |h| h[:authorization] = "Token token=\"#{Base64.strict_encode64 token.to_json}\"" h[:x_forwarded_for] = @remote_ip if @remote_ip end { headers: headers, username: username } end |
#current_role(account) ⇒ Conjur::Role
Return a Role object representing the role (typically a user or host) that this API instance is authenticated
as. This is derived either from the login
argument to new_from_key or from the contents of the
token
given to new_from_token or new_from_token_file.
75 76 77 |
# File 'lib/conjur/api/roles.rb', line 75 def current_role account self.class.role_from_username self, username, account end |
#init_from_key(username, api_key, remote_ip: nil, account: Conjur.configuration.account) ⇒ Object
258 259 260 261 262 263 264 |
# File 'lib/conjur/base.rb', line 258 def init_from_key username, api_key, remote_ip: nil, account: Conjur.configuration.account @username = username @api_key = api_key @remote_ip = remote_ip @authenticator = APIKeyAuthenticator.new(account, username, api_key) self end |
#init_from_token(token, remote_ip: nil) ⇒ Object
266 267 268 269 270 271 |
# File 'lib/conjur/base.rb', line 266 def init_from_token token, remote_ip: nil @token = token @remote_ip = remote_ip @authenticator = UnableAuthenticator.new self end |
#init_from_token_file(token_file, remote_ip: nil) ⇒ Object
273 274 275 276 277 |
# File 'lib/conjur/base.rb', line 273 def init_from_token_file token_file, remote_ip: nil @remote_ip = remote_ip @authenticator = TokenFileAuthenticator.new(token_file) self end |
#load_policy(id, policy, account: Conjur.configuration.account, method: POLICY_METHOD_POST) ⇒ Object
Load a policy document into the server.
The modes are support for policy loading:
- POLICY_METHOD_POST Policy data will be added to the named policy. Deletions are not allowed.
- POLICY_METHOD_PATCH Policy data can be added to or deleted from the named policy. Deletions
are performed by an explicit
!delete
statement. - POLICY_METHOD_PUT The policy completely replaces the name policy. Policy data which is present in the server, but not present in the new policy definition, is deleted.
49 50 51 52 |
# File 'lib/conjur/api/policies.rb', line 49 def load_policy id, policy, account: Conjur.configuration.account, method: POLICY_METHOD_POST request = RestClient::Resource.new(Conjur.configuration.core_url, credentials)['policies'][path_escape account]['policy'][path_escape id] PolicyLoadResult.new JSON.parse(request.send(method, policy)) end |
#resource(id) ⇒ Conjur::Resource
Find a resource by it's id. The id given to this method must be qualified by a kind, but the account is optional.
Permissions
The resource must be visible to the current role. This is the case if the current role is the owner of the resource, or has any privilege on it.
40 41 42 |
# File 'lib/conjur/api/resources.rb', line 40 def resource id build_object id end |
#resources(options = {}) ⇒ Array<Conjur::Resource>
Find all resources visible to the current role that match the given search criteria.
Full Text Search
Conjur supports full text search over the identifiers and annotation values
of resources. For example, if opts[:search]
is "pubkeys"
, any resource with
an id containing "pubkeys"
or an annotation whose value contains "pubkeys"
will match.
Notes
- Annotation keys are not indexed for full text search.
- Conjur indexes the content of ids and annotation values by word.
- Only resources visible to the current role (either owned by that role or having a privilege on it) are returned.
- If you do not provide
:offset
or:limit
, all records will be returned. For systems with a huge number of resources, you may want to paginate as shown in the example below. - If
:offset
is provided and:limit
is not, 10 records starting at:offset
will be returned. You may choose an arbitrarily large number for:limit
, but the same performance considerations apply as when omitting:offset
and:limit
.
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 |
# File 'lib/conjur/api/resources.rb', line 88 def resources = {} = { host: Conjur.configuration.core_url, credentials: credentials }.merge [:account] ||= Conjur.configuration.account host, credentials, account, kind = .values_at(*[:host, :credentials, :account, :kind]) fail ArgumentError, "host and account are required" unless [host, account].all? %w(host credentials account kind).each do |name| .delete(name.to_sym) end credentials ||= {} path = "/resources/#{path_escape account}" path += "/#{path_escape kind}" if kind result = JSON.parse(RestClient::Resource.new(Conjur.configuration.core_url, credentials)[path][ ].get) result = result['count'] if result.is_a?(Hash) if result.is_a?(Numeric) result else result.map do |result| resource(result['id']).tap do |r| r.attributes = result end end end end |
#revoke_host_factory_token(token) ⇒ Object
Revokes a host factory token. After revocation, the token can no longer be used to create hosts.
67 68 69 |
# File 'lib/conjur/api/host_factories.rb', line 67 def revoke_host_factory_token token self.class.revoke_host_factory_token credentials, token end |
#role(id) ⇒ Conjur::Role
Return a Role representing a role with the given id. Note that the Role may or may not exist (see Exists#exists?).
Permissions
Because this method returns roles that may or may not exist, it doesn't require any permissions to call it: in fact, it does not perform an HTTP request (except for authentication if necessary).
54 55 56 |
# File 'lib/conjur/api/roles.rb', line 54 def role id build_object id, default_class: Role end |
#token ⇒ Hash
The token used to authenticate requests made with the api. The token will be fetched, if possible, when not present or about to expire. Accordingly, this method may raise a RestClient::Unauthorized exception if the credentials are invalid.
137 138 139 140 |
# File 'lib/conjur/base.rb', line 137 def token refresh_token if needs_token_refresh? return @token end |
#username ⇒ String
The name of the user as which this api instance is authenticated. This is available whether the api instance was created from credentials or an authentication token.
120 121 122 |
# File 'lib/conjur/base.rb', line 120 def username @username || token['data'] end |
#variable_values(variable_ids) ⇒ Array<String>
Fetch the values of a list of variables. This operation is more efficient than fetching the values one by one.
This method will fail unless:
- All of the variables exist
- You have permission to
'execute'
all of the variables
This method is used to implement the conjur env
commands. You may consider using that instead to run your program in an environment with the necessary secrets.
50 51 52 53 54 55 56 57 58 59 60 61 |
# File 'lib/conjur/api/variables.rb', line 50 def variable_values variable_ids raise ArgumentError, "Variables list must be an array" unless variable_ids.kind_of? Array raise ArgumentError, "Variables list is empty" if variable_ids.empty? opts = "?variable_ids=#{variable_ids.map { |v| fully_escape(v) }.join(',')}" response = RestClient::Resource. new(Conjur.configuration.core_url,credentials)['secrets'+opts].get return JSON.parse(response.body) end |