Control groups
Overview
In some deployments, it may be desirable to require a "second set of eyes" to approve access to a secret or to generate a certificate. Control groups implement second-party authorization by means of policy "factors" applied to a path. When a control-group factor applies to a request, one or more members of the approving control group must assert authorization before the request can be executed and secret is released.
The workflow
The general flow for using control groups is as follows:
- A
control_groupstanza is declared in the policy for a path. - When a request for a path triggers the control group factor, the
response will be
wrapped. - The wrapped response will contain a
tokenand anaccessor. The requester needs to forward the accessor to a member of the approving group and request authorization. Please note: OpenBao does not send any notification to the approvers to tell them that they have a pending request. - The approvers can use the accessor to review the request, view the authorization state, and add their authorization.
- Once approved, the wrapping response token can "unwrap" the request (which executes the original request).
Control-group response wrapping
Response wrapping is triggered by requesting a path having one or more applicable control group factors in the policy. The original request is stored for deferred execution upon unwrapping.
- OpenBao makes a copy of the original API request, and stores it
- A new single-use token is generated with the TTL supplied by the factor
- OpenBao responds to the original request. Instead of performing the request directly and providing a response for the original request, the response from OpenBao is a wrap information object that includes: a. the token for executing the deferred response once approved b. an accessor for reviewing and approving the request c. a time to live (TTL) value for the token d. creation time of the original request e. creation path of the original request
Note that policies can control minimum/maximum wrapping TTLs; see the policies concepts page for more information.
Control-group operations
Via the sys/wrapping and sys/control-group paths, several
operations can be run against control-group wrapping tokens.
- Authorize (
sys/control-group/authorize): Using the accessor token, approve the request for deferred execution when unwrapped. - Review (
sys/control-group/request): Using the accessor token, view information about the original request (entity, path, payload, etc). - Unwrap (
sys/wrapping/unwrap): Unwrap the token, executing the original request and returning a response, once approved. The response that is returned will be an original wire-format response; it can be used directly with API clients. Note that the original request is processed only when unwrapping an approved request.
Control-group factors in ACL policies
Control groups are declared in a control-group stanza of an access control list (ACL) policy.
path "pki/issue/*" {
capabilities = ["read", "update"]
control_group = {
factor "pki-approvers" {
controlled_capabilities = ["update"]
identity {
# Control groups whose members can authorize access
group_names = ["pki-approvers", "security-team"]
approvals = 1
# Max duration for which authorization is valid
ttl = "5d"
# Allow self-authorization when true
self_authorization = false
}
}
}
}
Control Groups can verify the following factors:
- Identity Groups - Require an authorizer to be in a specific set of
identity groups. The
self_authorizationproperty indicates whether the original requester can self-authorize if they belong to the control group (default is false).
Controlled capabilities
Control group factors can be configured to trigger the control group
workflow on specific capabilities. This is done with the
controlled_capabilities field. Not specifying the
controlled_capabilities field will necessitate the factor to be
checked for all operations to the specified policy path. The
controlled_capabilities field can differ per factor, so that
different factors can be required for different operations.
Finally, the capabilities in the controlled_capabilities stanza must
be a subset of the capabilities specified in the policy itself. For
example, a policy giving only read access to the path secret/foo
cannot specify a control group factor with list as a controlled
capability.
Please see the following section for example ACL Policies.
Sample policies
path "secret/foo" {
capabilities = ["read"]
control_group = {
factor "ops_manager" {
identity {
group_names = ["managers"]
approvals = 1
}
}
}
}
The above policy grants read access to secret/foo only after one
member of the "managers" group authorizes the request. "managers"
group authorizes the request. If someone is a manager themselves, a
different manager must approve it (because self_auth_allowed
defaults to false).
path "secret/foo" {
capabilities = ["create", "update"]
control_group = {
ttl = "4h"
factor "tech leads" {
identity {
group_names = ["managers", "leads"]
approvals = 2
}
}
factor "super users" {
identity {
group_names = ["superusers"]
approvals = 1
}
}
}
}
The above policy grants create and update access to secret/foo
only after several conditions are met. The required conditions are
that:
- Two different users, who can be in either the "managers" or "leads" group (or both) have approved the request;
- One member of the "superusers" group has approved the request.
If an authorizer is a member of both the "managers" or "leads" and the "superusers" group, one approval for both factors will be recorded.
path "secret/foo" {
capabilities = ["create","update","read"]
control_group = {
factor "admin" {
controlled_capabilities = ["update"]
identity {
group_names = ["admin"]
approvals = 1
}
}
}
}
The above policy grants create and read access to secret/foo for
anyone that has a token with this policy. It grants update access to
secret/foo only after one member from the admin group authorizes the
request.
path "kv/*" {
capabilities = ["create","update","delete","list","sudo"]
control_group = {
factor "admin" {
controlled_capabilities = ["delete","list","sudo"]
identity {
group_names = ["admin"]
approvals = 1
}
}
}
}
path "kv/*" {
capabilities = ["create"]
control_group = {
factor "superuser" {
identity {
group_names = ["superuser"]
approvals = 2
}
}
}
}
Because the second path stanza has a control group factor with no
controlled_capabilities field, any token with this policy will be
required to get 2 approvals from the superuser group before
executing any operation against kv/*. In addition, by virtue of the
controlled_capabilities field in the first path stanza,
delete,list, and sudo operations will require an additional
approval from the admin group.
path "kv/*" {
capabilities = ["read","list","create"]
control_group = {
factor "admin" {
controlled_capabilities = ["read"]
identity {
group_names = ["admin"]
approvals = 1
}
}
factor "superuser" {
controlled_capabilities = ["create"]
identity {
group_names = ["superuser"]
approvals = 1
}
}
}
}
In this case, read will require one admin approval and create will
require one superuser approval. list will require no approvals from
any of the control group factors, and a token with this policy will
not be required to go through the control group workflow in order to
execute a list operation against kv/*.