The auth system for Swift is loosely based on the auth system from the existing Rackspace architecture – actually from a few existing auth systems – and is therefore a bit disjointed. The distilled points about it are:
The token can be passed into Swift using the X-Auth-Token or the X-Storage-Token header. Both have the same format: just a simple string representing the token. Some auth systems use UUID tokens, some an MD5 hash of something unique, some use “something else” but the salient point is that the token is a string which can be sent as-is back to the auth system for validation.
Swift will make calls to the auth system, giving the auth token to be validated. For a valid token, the auth system responds with an overall expiration in seconds from now. Swift will cache the token up to the expiration time.
The included TempAuth also has the concept of admin and non-admin users within an account. Admin users can do anything within the account. Non-admin users can only perform operations per container based on the container’s X-Container-Read and X-Container-Write ACLs. Container ACLs use the “V1” ACL syntax, which looks like this: name1, name2, .r:referrer1.com, .r:-bad.referrer1.com, .rlistings For more information on ACLs, see swift.common.middleware.acl.
Additionally, if the auth system sets the request environ’s swift_owner key to True, the proxy will return additional header information in some requests, such as the X-Container-Sync-Key for a container GET or HEAD.
In addition to container ACLs, TempAuth allows account-level ACLs. Any auth system may use the special header X-Account-Access-Control to specify account-level ACLs in a format specific to that auth system. (Following the TempAuth format is strongly recommended.) These headers are visible and settable only by account owners (those for whom swift_owner is true). Behavior of account ACLs is auth-system-dependent. In the case of TempAuth, if an authenticated user has membership in a group which is listed in the ACL, then the user is allowed the access level of that ACL.
Account ACLs use the “V2” ACL syntax, which is a JSON dictionary with keys named “admin”, “read-write”, and “read-only”. (Note the case sensitivity.) An example value for the X-Account-Access-Control header looks like this: {"admin":["a","b"],"read-only":["c"]} Keys may be absent (as shown). The recommended way to generate ACL strings is as follows:
from swift.common.middleware.acl import format_acl
acl_data = { 'admin': ['alice'], 'read-write': ['bob', 'carol'] }
acl_string = format_acl(version=2, acl_dict=acl_data)
Using the format_acl() method will ensure that JSON is encoded as ASCII (using e.g. ‘u1234’ for Unicode). While it’s permissible to manually send curl commands containing X-Account-Access-Control headers, you should exercise caution when doing so, due to the potential for human error.
Within the JSON dictionary stored in X-Account-Access-Control, the keys have the following meanings:
Access Level | Description |
---|---|
read-only | These identities can read everything (except privileged headers) in the account. Specifically, a user with read-only account access can get a list of containers in the account, list the contents of any container, retrieve any object, and see the (non-privileged) headers of the account, any container, or any object. |
read-write | These identities can read or write (or create) any container. A user with read-write account access can create new containers, set any unprivileged container headers, overwrite objects, delete containers, etc. A read-write user can NOT set account headers (or perform any PUT/POST/DELETE requests on the account). |
admin | These identities have “swift_owner” privileges. A user with admin account access can do anything the account owner can, including setting account headers and any privileged headers – and thus granting read-only, read-write, or admin access to other users. |
For more details, see swift.common.middleware.tempauth. For details on the ACL format, see swift.common.middleware.acl.
Users with the special group .reseller_admin can operate on any account. For an example usage please see swift.common.middleware.tempauth. If a request is coming from a reseller the auth system sets the request environ reseller_request to True. This can be used by other middlewares.
TempAuth will now allow OPTIONS requests to go through without a token.
The user starts a session by sending a REST request to the auth system to receive the auth token and a URL to the Swift system.
Swift is able to authenticate against OpenStack Keystone via the KeystoneAuth middleware.
In order to use the keystoneauth middleware the auth_token middleware from KeystoneMiddleware will need to be configured.
The authtoken middleware performs the authentication token validation and retrieves actual user authentication information. It can be found in the KeystoneMiddleware distribution.
The KeystoneAuth middleware performs authorization and mapping the Keystone roles to Swift’s ACLs.
Configuring Swift to use Keystone is relatively straight forward. The first step is to ensure that you have the auth_token middleware installed. It can either be dropped in your python path or installed via the KeystoneMiddleware package.
You need at first make sure you have a service endpoint of type object-store in Keystone pointing to your Swift proxy. For example having this in your /etc/keystone/default_catalog.templates
catalog.RegionOne.object_store.name = Swift Service
catalog.RegionOne.object_store.publicURL = http://swiftproxy:8080/v1/AUTH_$(tenant_id)s
catalog.RegionOne.object_store.adminURL = http://swiftproxy:8080/
catalog.RegionOne.object_store.internalURL = http://swiftproxy:8080/v1/AUTH_$(tenant_id)s
On your Swift proxy server you will want to adjust your main pipeline and add auth_token and keystoneauth in your /etc/swift/proxy-server.conf like this
[pipeline:main]
pipeline = [....] authtoken keystoneauth proxy-logging proxy-server
add the configuration for the authtoken middleware:
[filter:authtoken]
paste.filter_factory = keystonemiddleware.auth_token:filter_factory
auth_uri = http://keystonehost:5000/
auth_url = http://keystonehost:35357/
auth_plugin = password
project_domain_id = default
user_domain_id = default
project_name = service
username = swift
password = password
cache = swift.cache
include_service_catalog = False
delay_auth_decision = True
The actual values for these variables will need to be set depending on your situation, but in short:
Note
The authtoken config variable delay_auth_decision must be set to True. The default is False, but that breaks public access, StaticWeb, FormPost, TempURL, and authenticated capabilities requests (using Discoverability).
and you can finally add the keystoneauth configuration. Here is a simple configuration:
[filter:keystoneauth]
use = egg:swift#keystoneauth
operator_roles = admin, swiftoperator
Use an appropriate list of roles in operator_roles. For example, in some systems, the role _member_ or Member is used to indicate that the user is allowed to operate on project resources.
Some OpenStack services such as Cinder and Glance may use a “service account”. In this mode, you configure a separate account where the service stores project data that it manages. This account is not used directly by the end-user. Instead, all access is done through the service.
To access the “service” account, the service must present two tokens: one from the end-user and another from its own service user. Only when both tokens are present can the account be accessed. This section describes how to set the configuration options to correctly control access to both the “normal” and “service” accounts.
In this example, end users use the AUTH_ prefix in account names, whereas services use the SERVICE_ prefix:
[filter:keystoneauth]
use = egg:swift#keystoneauth
reseller_prefix = AUTH, SERVICE
operator_roles = admin, swiftoperator
SERVICE_service_roles = service
The actual values for these variable will need to be set depending on your situation as follows:
This configuration works as follows:
In the above example, all services share the same account. You can separate each service into its own account. For example, the following provides a dedicated account for each of the Glance and Cinder services. In addition, you must assign the glance_service and cinder_service to the appropriate service users:
[filter:keystoneauth]
use = egg:swift#keystoneauth
reseller_prefix = AUTH, IMAGE, VOLUME
operator_roles = admin, swiftoperator
IMAGE_service_roles = glance_service
VOLUME_service_roles = cinder_service
By default the only users able to perform operations (e.g. create a container) on an account are those having a Keystone role for the corresponding Keystone project that matches one of the roles specified in the operator_roles option.
Users who have one of the operator_roles will be able to set container ACLs to grant other users permission to read and/or write objects in specific containers, using X-Container-Read and X-Container-Write headers respectively. In addition to the ACL formats described here, keystoneauth supports ACLs using the format:
other_project_id:other_user_id.
where other_project_id is the UUID of a Keystone project and other_user_id is the UUID of a Keystone user. This will allow the other user to access a container provided their token is scoped on the other project. Both other_project_id and other_user_id may be replaced with the wildcard character * which will match any project or user respectively.
Be sure to use Keystone UUIDs rather than names in container ACLs.
Note
For backwards compatibility, keystoneauth will by default grant container ACLs expressed as other_project_name:other_user_name (i.e. using Keystone names rather than UUIDs) in the special case when both the other project and the other user are in Keystone’s default domain and the project being accessed is also in the default domain.
For further information see KeystoneAuth
Users with the Keystone role defined in reseller_admin_role (ResellerAdmin by default) can operate on any account. The auth system sets the request environ reseller_request to True if a request is coming from a user with this role. This can be used by other middlewares.
Some common mistakes can result in API requests failing when first deploying keystone with Swift:
Incorrect configuration of the Swift endpoint in the Keystone service.
By default, keystoneauth expects the account part of a URL to have the form AUTH_<keystone_project_id>. Sometimes the AUTH_ prefix is missed when configuring Swift endpoints in Keystone, as described in the Install Guide. This is easily diagnosed by inspecting the proxy-server log file for a failed request URL and checking that the URL includes the AUTH_ prefix (or whatever reseller prefix may have been configured for keystoneauth):
GOOD:
proxy-server: 127.0.0.1 127.0.0.1 07/Sep/2016/16/06/58 HEAD /v1/AUTH_cfb8d9d45212408b90bc0776117aec9e HTTP/1.0 204 ...
BAD:
proxy-server: 127.0.0.1 127.0.0.1 07/Sep/2016/16/07/35 HEAD /v1/cfb8d9d45212408b90bc0776117aec9e HTTP/1.0 403 ...
Incorrect configuration of the authtoken middleware options in the Swift proxy server.
The authtoken middleware communicates with the Keystone service to validate tokens that are presented with client requests. To do this authtoken must authenticate itself with Keystone using the credentials configured in the [filter:authtoken] section of /etc/swift/proxy-server.conf. Errors in these credentials can result in authtoken failing to validate tokens and may be revealed in the proxy server logs by a message such as:
proxy-server: Identity server rejected authorization
Note
More detailed log messaging may be seen by setting the authtoken option log_level = debug.
The authtoken configuration options may be checked by attempting to use them to communicate directly with Keystone using an openstack command line. For example, given the authtoken configuration sample shown in Configuring Swift to use Keystone, the following command should return a service catalog:
openstack --os-identity-api-version=3 --os-auth-url=http://keystonehost:5000/ \
--os-username=swift --os-user-domain-id=default \
--os-project-name=service --os-project-domain-id=default \
--os-password=password catalog show object-store
If this openstack command fails then it is likely that there is a problem with the authtoken configuration.
TempAuth is written as wsgi middleware, so implementing your own auth is as easy as writing new wsgi middleware, and plugging it in to the proxy server. The Keystone project and the Swauth project are examples of additional auth services.
Also, see Auth Server and Middleware.