etc/keystone.conf.sample
[DEFAULT] # A "shared secret" between keystone and other openstack services # admin_token = ADMIN # The IP address of the network interface to listen on # bind_host = 0.0.0.0 # The port number which the public service listens on # public_port = 5000 # The port number which the public admin listens on # admin_port = 35357 # The base endpoint URLs for keystone that are advertised to clients # (NOTE: this does NOT affect how keystone listens for connections) # public_endpoint = http://localhost:%(public_port)s/ # admin_endpoint = http://localhost:%(admin_port)s/ # The port number which the OpenStack Compute service listens on # compute_port = 8774 # Path to your policy definition containing identity actions # policy_file = policy.json # Rule to check if no matching policy definition is found # FIXME(dolph): This should really be defined as [policy] default_rule # policy_default_rule = admin_required # Role for migrating membership relationships # During a SQL upgrade, the following values will be used to create a new role # that will replace records in the user_tenant_membership table with explicit # role grants. After migration, the member_role_id will be used in the API # add_user_to_project, and member_role_name will be ignored. # member_role_id = 9fe2ff9ee4384b1894a90878d3e92bab # member_role_name = _member_ # enforced by optional sizelimit middleware (keystone.middleware:RequestBodySizeLimiter) # max_request_body_size = 114688 # limit the sizes of user & tenant ID/names # max_param_size = 64 # similar to max_param_size, but provides an exception for token values # max_token_size = 8192 # === Logging Options === # Print debugging output # (includes plaintext request logging, potentially including passwords) # debug = False # Print more verbose output # verbose = False # Name of log file to output to. If not set, logging will go to stdout. # log_file = keystone.log # The directory to keep log files in (will be prepended to --logfile) # log_dir = /var/log/keystone # Use syslog for logging. # use_syslog = False # syslog facility to receive log lines # syslog_log_facility = LOG_USER # If this option is specified, the logging configuration file specified is # used and overrides any other logging options specified. Please see the # Python logging module documentation for details on logging configuration # files. # log_config = logging.conf # A logging.Formatter log message format string which may use any of the # available logging.LogRecord attributes. # log_format = %(asctime)s %(levelname)8s [%(name)s] %(message)s # Format string for %(asctime)s in log records. # log_date_format = %Y-%m-%d %H:%M:%S # onready allows you to send a notification when the process is ready to serve # For example, to have it notify using systemd, one could set shell command: # onready = systemd-notify --ready # or a module with notify() method: # onready = keystone.common.systemd [sql] # The SQLAlchemy connection string used to connect to the database # connection = sqlite:///keystone.db # the timeout before idle sql connections are reaped # idle_timeout = 200 [identity] # driver = keystone.identity.backends.sql.Identity # This references the domain to use for all Identity API v2 requests (which are # not aware of domains). A domain with this ID will be created for you by # keystone-manage db_sync in migration 008. The domain referenced by this ID # cannot be deleted on the v3 API, to prevent accidentally breaking the v2 API. # There is nothing special about this domain, other than the fact that it must # exist to order to maintain support for your v2 clients. # default_domain_id = default [credential] # driver = keystone.credential.backends.sql.Credential [trust] # driver = keystone.trust.backends.sql.Trust # delegation and impersonation features can be optionally disabled # enabled = True [os_inherit] # role-assignment inheritance to projects from owning domain can be # optionally enabled # enabled = False [catalog] # dynamic, sql-based backend (supports API/CLI-based management commands) # driver = keystone.catalog.backends.sql.Catalog # static, file-based backend (does *NOT* support any management commands) # driver = keystone.catalog.backends.templated.TemplatedCatalog # template_file = default_catalog.templates [token] # Provides token persistence. # driver = keystone.token.backends.sql.Token # Controls the token construction, validation, and revocation operations. # Core providers are keystone.token.providers.[pki|uuid].Provider # provider = # Amount of time a token should remain valid (in seconds) # expiration = 86400 # External auth mechanisms that should add bind information to token. # eg kerberos, x509 # bind = # Enforcement policy on tokens presented to keystone with bind information. # One of disabled, permissive, strict, required or a specifically required bind # mode e.g. kerberos or x509 to require binding to that authentication. # enforce_token_bind = permissive [policy] # driver = keystone.policy.backends.sql.Policy [ec2] # driver = keystone.contrib.ec2.backends.kvs.Ec2 [assignment] # driver = [ssl] #enable = True #certfile = /etc/keystone/pki/certs/ssl_cert.pem #keyfile = /etc/keystone/pki/private/ssl_key.pem #ca_certs = /etc/keystone/pki/certs/cacert.pem #ca_key = /etc/keystone/pki/private/cakey.pem #key_size = 1024 #valid_days = 3650 #ca_password = None #cert_required = False #cert_subject = /C=US/ST=Unset/L=Unset/O=Unset/CN=localhost [signing] # Deprecated in favor of provider in the [token] section # Allowed values are PKI or UUID #token_format = #certfile = /etc/keystone/pki/certs/signing_cert.pem #keyfile = /etc/keystone/pki/private/signing_key.pem #ca_certs = /etc/keystone/pki/certs/cacert.pem #ca_key = /etc/keystone/pki/private/cakey.pem #key_size = 2048 #valid_days = 3650 #ca_password = None #cert_subject = /C=US/ST=Unset/L=Unset/O=Unset/CN=www.example.com [ldap] # url = ldap://localhost # user = dc=Manager,dc=example,dc=com # password = None # suffix = cn=example,cn=com # use_dumb_member = False # allow_subtree_delete = False # dumb_member = cn=dumb,dc=example,dc=com # Maximum results per page; a value of zero ('0') disables paging (default) # page_size = 0 # The LDAP dereferencing option for queries. This can be either 'never', # 'searching', 'always', 'finding' or 'default'. The 'default' option falls # back to using default dereferencing configured by your ldap.conf. # alias_dereferencing = default # The LDAP scope for queries, this can be either 'one' # (onelevel/singleLevel) or 'sub' (subtree/wholeSubtree) # query_scope = one # user_tree_dn = ou=Users,dc=example,dc=com # user_filter = # user_objectclass = inetOrgPerson # user_domain_id_attribute = businessCategory # user_id_attribute = cn # user_name_attribute = sn # user_mail_attribute = email # user_pass_attribute = userPassword # user_enabled_attribute = enabled # user_enabled_mask = 0 # user_enabled_default = True # user_attribute_ignore = tenant_id,tenants # user_allow_create = True # user_allow_update = True # user_allow_delete = True # user_enabled_emulation = False # user_enabled_emulation_dn = # tenant_tree_dn = ou=Projects,dc=example,dc=com # tenant_filter = # tenant_objectclass = groupOfNames # tenant_domain_id_attribute = businessCategory # tenant_id_attribute = cn # tenant_member_attribute = member # tenant_name_attribute = ou # tenant_desc_attribute = desc # tenant_enabled_attribute = enabled # tenant_attribute_ignore = # tenant_allow_create = True # tenant_allow_update = True # tenant_allow_delete = True # tenant_enabled_emulation = False # tenant_enabled_emulation_dn = # role_tree_dn = ou=Roles,dc=example,dc=com # role_filter = # role_objectclass = organizationalRole # role_id_attribute = cn # role_name_attribute = ou # role_member_attribute = roleOccupant # role_attribute_ignore = # role_allow_create = True # role_allow_update = True # role_allow_delete = True # group_tree_dn = # group_filter = # group_objectclass = groupOfNames # group_id_attribute = cn # group_name_attribute = ou # group_member_attribute = member # group_desc_attribute = desc # group_attribute_ignore = # group_allow_create = True # group_allow_update = True # group_allow_delete = True # ldap TLS options # if both tls_cacertfile and tls_cacertdir are set then # tls_cacertfile will be used and tls_cacertdir is ignored # valid options for tls_req_cert are demand, never, and allow # use_tls = False # tls_cacertfile = # tls_cacertdir = # tls_req_cert = demand # Additional attribute mappings can be used to map ldap attributes to internal # keystone attributes. This allows keystone to fulfill ldap objectclass # requirements. An example to map the description and gecos attributes to a # user's name would be: # user_additional_attribute_mapping = description:name, gecos:name # # domain_additional_attribute_mapping = # group_additional_attribute_mapping = # role_additional_attribute_mapping = # project_additional_attribute_mapping = # user_additional_attribute_mapping = [auth] methods = external,password,token #external = keystone.auth.plugins.external.ExternalDefault password = keystone.auth.plugins.password.Password token = keystone.auth.plugins.token.Token [paste_deploy] # Name of the paste configuration file that defines the available pipelines config_file = keystone-paste.ini
etc/keystone-paste.ini
# Keystone PasteDeploy configuration file. [filter:debug] paste.filter_factory = keystone.common.wsgi:Debug.factory [filter:token_auth] paste.filter_factory = keystone.middleware:TokenAuthMiddleware.factory [filter:admin_token_auth] paste.filter_factory = keystone.middleware:AdminTokenAuthMiddleware.factory [filter:xml_body] paste.filter_factory = keystone.middleware:XmlBodyMiddleware.factory [filter:json_body] paste.filter_factory = keystone.middleware:JsonBodyMiddleware.factory [filter:user_crud_extension] paste.filter_factory = keystone.contrib.user_crud:CrudExtension.factory [filter:crud_extension] paste.filter_factory = keystone.contrib.admin_crud:CrudExtension.factory [filter:ec2_extension] paste.filter_factory = keystone.contrib.ec2:Ec2Extension.factory [filter:s3_extension] paste.filter_factory = keystone.contrib.s3:S3Extension.factory [filter:url_normalize] paste.filter_factory = keystone.middleware:NormalizingFilter.factory [filter:sizelimit] paste.filter_factory = keystone.middleware:RequestBodySizeLimiter.factory [filter:stats_monitoring] paste.filter_factory = keystone.contrib.stats:StatsMiddleware.factory [filter:stats_reporting] paste.filter_factory = keystone.contrib.stats:StatsExtension.factory [filter:access_log] paste.filter_factory = keystone.contrib.access:AccessLogMiddleware.factory [app:public_service] paste.app_factory = keystone.service:public_app_factory [app:service_v3] paste.app_factory = keystone.service:v3_app_factory [app:admin_service] paste.app_factory = keystone.service:admin_app_factory [pipeline:public_api] pipeline = access_log sizelimit url_normalize token_auth admin_token_auth xml_body json_body ec2_extension user_crud_extension public_service [pipeline:admin_api] pipeline = access_log sizelimit url_normalize token_auth admin_token_auth xml_body json_body ec2_extension s3_extension crud_extension admin_service [pipeline:api_v3] pipeline = access_log sizelimit url_normalize token_auth admin_token_auth xml_body json_body ec2_extension s3_extension service_v3 [app:public_version_service] paste.app_factory = keystone.service:public_version_app_factory [app:admin_version_service] paste.app_factory = keystone.service:admin_version_app_factory [pipeline:public_version_api] pipeline = access_log sizelimit url_normalize xml_body public_version_service [pipeline:admin_version_api] pipeline = access_log sizelimit url_normalize xml_body admin_version_service [composite:main] use = egg:Paste#urlmap /v2.0 = public_api /v3 = api_v3 / = public_version_api [composite:admin] use = egg:Paste#urlmap /v2.0 = admin_api /v3 = api_v3 / = admin_version_api
etc/logging.conf.sample
[loggers] keys=root,access [handlers] keys=production,file,access_file,devel [formatters] keys=minimal,normal,debug ########### # Loggers # ########### [logger_root] level=WARNING handlers=file [logger_access] level=INFO qualname=access handlers=access_file ################ # Log Handlers # ################ [handler_production] class=handlers.SysLogHandler level=ERROR formatter=normal args=(('localhost', handlers.SYSLOG_UDP_PORT), handlers.SysLogHandler.LOG_USER) [handler_file] class=handlers.WatchedFileHandler level=WARNING formatter=normal args=('error.log',) [handler_access_file] class=handlers.WatchedFileHandler level=INFO formatter=minimal args=('access.log',) [handler_devel] class=StreamHandler level=NOTSET formatter=debug args=(sys.stdout,) ################## # Log Formatters # ################## [formatter_minimal] format=%(message)s [formatter_normal] format=(%(name)s): %(asctime)s %(levelname)s %(message)s [formatter_debug] format=(%(name)s): %(asctime)s %(levelname)s %(module)s %(funcName)s %(message)s
Running Identity is simply starting the services by using the command:
keystone-all
Invoking this command starts up two wsgi.Server instances, configured by the keystone.conf
and keystone-paste.ini
files as described above. One of these wsgi 'servers' is admin
(the administration API) and the other is main
(the primary/public API interface). Both of these run in a single process.
keystone-manage is designed to execute commands that cannot be administered through the normal REST api. At the moment, the following calls are supported:
db_sync
: Sync the database.
import_nova_auth
: Load auth data from a dump created with keystone-manage.
Generally, the following is the first step after a source installation:
keystone-manage db_sync
Invoking keystone-manage by itself will give you additional usage information.
Only users with admin credentials can administer users, tenants and roles. You can configure the python-keystoneclient with admin credentials through either the authentication token, or the username and password method.
To use keystone client using token auth, set the following flags:
--endpoint SERVICE_ENDPOINT
. The keystone endpoint to communicate with. The default endpoint is http://localhost:35357/v2.0'.
--token SERVICE_TOKEN
. The administrator service token.
--username OS_USERNAME
. The administrator username.
--password OS_PASSWORD
. The administrator password
--tenant_name OS_TENANT_NAME
. The tenant name.
--auth_url OS_AUTH_URL
. The URL of the keystone auth server, for example http://localhost:5000/v2.0'.
Use the following keystone parameters, in combination, to specify the version of the API to use:
--os-endpoint
. The keystone
client detects the version of the API from this parameter.
--os-url
. Specifies the service URL from the service catalog lookup.
--os-identity-api-version
. Specifies the Identity Service API version.
For example, the following parameters indicate the use of API v3:
--os-url "http://15.253.57.115:35357/v3" --os-identity-api-version 3
The following parameters indicate the use of API v2.0:
--os-url "http://15.253.57.115:35357/v2.0" --os-identity-api-version 2.0
The keystone
client is set up to expect commands in the general form of keystone
command
argument
, followed by flag-like keyword arguments to provide additional (often optional) information. For example, the command user-list
and tenant-create
can be invoked as follows:
# Using token auth env variables export SERVICE_ENDPOINT=http://127.0.0.1:5000/v2.0/ export SERVICE_TOKEN=secrete_token keystone user-list keystone tenant-create --name=demo # Using token auth flags keystone --token=secrete --endpoint=http://127.0.0.1:5000/v2.0/ user-list keystone --token=secrete --endpoint=http://127.0.0.1:5000/v2.0/ tenant-create --name=demo # Using user + password + tenant_name env variables export OS_USERNAME=admin export OS_PASSWORD=secrete export OS_TENANT_NAME=admin keystone user-list keystone tenant-create --name=demo # Using user + password + tenant_name flags keystone --username=admin --password=secrete --tenant_name=admin user-list keystone --username=admin --password=secrete --tenant_name=admin tenant-create --name=demo
tenant-create
tenant-delete
tenant-enable
tenant-disable
A tenant is a group of zero or more users. In nova, a tenant owns virtual machines. In swift, a tenant owns containers. Users can be associated with more than one tenant. Each tenant and user pairing can have a role associated with it.
tenant-create
keyword arguments
name
description (optional, defaults to None)
enabled (optional, defaults to True)
The following command creates a tenant named demo:
keystone tenant-create --name=demo
tenant-delete
arguments
tenant_id
example:
keystone tenant-delete f2b7b39c860840dfa47d9ee4adffa0b3
tenant-enable
arguments
tenant_id
example:
keystone tenant-enable f2b7b39c860840dfa47d9ee4adffa0b3
tenant-disable
arguments
tenant_id
example:
keystone tenant-disable f2b7b39c860840dfa47d9ee4adffa0b3
user-create
user-delete
user-list
user-update --email
user-enable
user-disable
user-update --password
user-create
keyword arguments:
name
pass
default_tenant (optional, defaults to None)
enabled (optional, defaults to True)
example:
keystone user-create --name=admin \ --pass=secrete \ [email protected]
user-delete
keyword arguments:
user
example:
keystone user-delete f2b7b39c860840dfa47d9ee4adffa0b3
user-list
list users in the system, optionally by a specific tenant (identified by tenant_id)
arguments
tenant_id (optional, defaults to None)
example:
keystone user-list
user-update --email
arguments
user_id
example:
keystone user-update --email 03c84b51574841ba9a0d8db7882ac645 "[email protected]"
user-enable
arguments
user_id
example:
keystone user-enable 03c84b51574841ba9a0d8db7882ac645
user-disable
arguments
user_id
example:
keystone user-disable 03c84b51574841ba9a0d8db7882ac645
user-update --password
arguments
user_id
password
example:
keystone user-update --password 03c84b51574841ba9a0d8db7882ac645 foo
role-create
role-delete
role-list
role-get
add-user-role
remove-user-role
role-create
arguments
name
example:
keystone role-create --name=demo
role-delete
arguments
role_id
example:
keystone role-delete 19d1d3344873464d819c45f521ff9890
role-list
example:
keystone role-list
role-get
arguments
role_id
example:
keystone role-get role=19d1d3344873464d819c45f521ff9890
add-user-role
arguments
role_id
user_id
tenant_id
example:
keystone add-user-role \ 3a751f78ef4c412b827540b829e2d7dd \ 03c84b51574841ba9a0d8db7882ac645 \ 20601a7f1d94447daa4dff438cb1c209
remove-user-role
arguments
role_id
user_id
tenant_id
example:
keystone remove-user-role \ 19d1d3344873464d819c45f521ff9890 \ 08741d8ed88242ca88d1f61484a0fe3b \ 20601a7f1d94447daa4dff438cb1c209
service-create
service-list
service-get
service-delete
service-create
keyword arguments
name
type
description
example:
keystone service create \ --name=nova \ --type=compute \ --description="Nova Compute Service"
service-list
arguments
service_id
example:
keystone service-list
service-get
arguments
service_id
example:
keystone service-get 08741d8ed88242ca88d1f61484a0fe3b
service-delete
arguments
service_id
example:
keystone service-delete 08741d8ed88242ca88d1f61484a0fe3b
Once Keystone is installed and running, services need to be configured to work with it. To do this, we primarily install and configure middleware for the OpenStack service to handle authentication tasks or otherwise interact with Keystone.
In general:
Clients making calls to the service will pass in an authentication token.
The Keystone middleware will look for and validate that token, taking the appropriate action.
It will also retrieve additional information from the token such as user name, id, tenant name, id, roles, etc...
The middleware will pass those data down to the service as headers.
The Keystone auth_token middleware is a WSGI component that can be inserted in the WSGI pipeline to handle authenticating tokens with Keystone.
When configuring Nova, it is important to create a nova user in the service tenant and include the nova user's login information in /etc/nova/nova.conf
Similar to Nova, swift can be configured to use Keystone for authentication rather than its built in 'tempauth'.
Add a service endpoint for Swift to Keystone
Configure the paste file for swift-proxy, /etc/swift/proxy-server.conf
.
Reconfigure Swift's proxy server to use Keystone instead of TempAuth. Here's an example `/etc/swift/proxy-server.conf`:
[DEFAULT] bind_port = 8888 user =[pipeline:main] pipeline = catch_errors healthcheck cache authtoken keystone proxy-server [app:proxy-server] use = egg:swift#proxy account_autocreate = true [filter:keystone] paste.filter_factory = keystoneclient.middleware.swift_auth:filter_factory operator_roles = admin, swiftoperator [filter:authtoken] paste.filter_factory = keystoneclient.middleware.auth_token:filter_factory # Delaying the auth decision is required to support token-less # usage for anonymous referrers ('.r:*'). delay_auth_decision = 10 service_port = 5000 service_host = 127.0.0.1 auth_port = 35357 auth_host = 127.0.0.1 auth_token = ADMIN admin_token = ADMIN cache = swift.cache [filter:cache] use = egg:swift#memcache set log_name = cache [filter:catch_errors] use = egg:swift#catch_errors [filter:healthcheck] use = egg:swift#healthcheck
Restart swift services.
Verify that the Identity service, Keystone, is providing authentication to Object Storage (Swift).
$ swift -V 2 -A http://localhost:5000/v2.0 -U admin:admin -K ADMIN stat
Keystone support validating S3 tokens using the same tokens as the generated EC2 tokens. When you have generated a pair of EC2 access token and secret you can access your swift cluster directly with the S3 API.
Configure the paste file for swift-proxy (`/etc/swift/proxy-server.conf`) to use S3token and Swift3 middleware. You must have the s3token middleware in the pipeline when using keystone and swift3.
Here's an example:
[DEFAULT] bind_port = 8080 user =[pipeline:main] pipeline = catch_errors healthcheck cache swift3 s3token authtoken keystone proxy-server [app:proxy-server] use = egg:swift#proxy account_autocreate = true [filter:catch_errors] use = egg:swift#catch_errors [filter:healthcheck] use = egg:swift#healthcheck [filter:cache] use = egg:swift#memcache [filter:swift3] use = egg:swift#swift3 [filter:keystone] paste.filter_factory = keystoneclient.middleware.swift_auth:filter_factory operator_roles = admin, swiftoperator [filter:s3token] paste.filter_factory = keystoneclient.middleware.s3_token:filter_factory auth_port = 35357 auth_host = 127.0.0.1 auth_protocol = http [filter:authtoken] paste.filter_factory = keystoneclient.middleware.auth_token:filter_factory service_port = 5000 service_host = 127.0.0.1 auth_port = 35357 auth_host = 127.0.0.1 auth_protocol = http auth_token = ADMIN admin_token = ADMIN
You can then access directly your Swift via the S3 API, here's an example with the `boto` library:
import boto import boto.s3.connection connection = boto.connect_s3( aws_access_key_id='', aws_secret_access_key=' ', port=8080, host='localhost', is_secure=False, calling_format=boto.s3.connection.OrdinaryCallingFormat())
As an alternative to the SQL Database backing store, Keystone can use a directory server to provide the Identity service. An example Schema for OpenStack would look like this:
dn: dc=openstack,dc=org dc: openstack objectClass: dcObject objectClass: organizationalUnit ou: openstack dn: ou=UserGroups,dc=openstack,dc=org objectClass: organizationalUnit ou: UserGroups dn: ou=Users,dc=openstack,dc=org objectClass: organizationalUnit ou: Users dn: ou=Roles,dc=openstack,dc=org objectClass: organizationalUnit ou: Roles dn: ou=Projects,dc=openstack,dc=org objectClass: organizationalUnit ou: Projects dn: cn=9fe2ff9ee4384b1894a90878d3e92bab,ou=Roles,dc=openstack,dc=org objectClass: organizationalRole ou: _member_ cn: 9fe2ff9ee4384b1894a90878d3e92bab
The corresponding entries in the Keystone configuration file are:
[DEFAULT] public_endpoint = http://localhost:%(public_port)s/ admin_endpoint = http://localhost:%(admin_port)s/ member_role_id = 9fe2ff9ee4384b1894a90878d3e92bab member_role_name = _member_ [ldap] url = ldap://localhost user = dc=Manager,dc=openstack,dc=org password = badpassword suffix = dc=openstack,dc=org use_dumb_member = True user_tree_dn = ou=Users,dc=openstack,dc=org user_domain_id_attribute = businessCategory user_attribute_ignore = enabled,email,tenants,tenantId tenant_tree_dn = ou=Projects,dc=openstack,dc=org tenant_desc_attribute = description tenant_domain_id_attribute = businessCategory tenant_attribute_ignore = enabled role_tree_dn = ou=Roles,dc=openstack,dc=org
The default object classes and attributes are intentionally simplistic. They reflect the common standard objects according to the LDAP RFCs. However, in a live deployment, the correct attributes can be overridden to support a preexisting, more complex schema. For example, in the user object, the objectClass posixAccount from RFC2307 is very common. If this is the underlying objectclass, then the uid field should probably be uidNumber andusername field either uid or cn. To change these two fields, the corresponding entries in the Keystone configuration file are:
[ldap] user_id_attribute = uidNumber user_name_attribute = cn
There is a set of allowed actions per object type that you can modify depending on your specific deployment. For example, the users are managed by another tool and you have only read access, in such case the configuration is:
[ldap] user_allow_create = False user_allow_update = False user_allow_delete = False tenant_allow_create = True tenant_allow_update = True tenant_allow_delete = True role_allow_create = True role_allow_update = True role_allow_delete = True
There are some configuration options for filtering users, tenants and roles, if the backend is providing too much output, in such case the configuration will look like:
[ldap] user_filter = (memberof=CN=openstack-users,OU=workgroups,DC=openstack,DC=com) tenant_filter = role_filter =
In case that the directory server does not have an attribute enabled of type boolean for the user, there are several configuration parameters that can be used to extract the value from an integer attribute like in Active Directory:
[ldap] user_enabled_attribute = userAccountControl user_enabled_mask = 2 user_enabled_default = 512
In this case the attribute is an integer and the enabled attribute is listed in bit 1, so the if the mask configured user_enabled_mask is different from 0, it gets the value from the field user_enabled_attribute and it makes an ADD operation with the value indicated on user_enabled_mask and if the value matches the mask then the account is disabled.
It also saves the value without mask to the user identity in the attribute enabled_nomask. This is needed in order to set it back in case that we need to change it to enable/disable a user because it contains more information than the status like password expiration. Last setting user_enabled_mask is needed in order to create a default value on the integer attribute (512 = NORMAL ACCOUNT on AD)
In case of Active Directory the classes and attributes could not match the specified classes in the LDAP module so you can configure them like so:
[ldap] user_objectclass = person user_id_attribute = cn user_name_attribute = cn user_mail_attribute = mail user_enabled_attribute = userAccountControl user_enabled_mask = 2 user_enabled_default = 512 user_attribute_ignore = tenant_id,tenants tenant_objectclass = groupOfNames tenant_id_attribute = cn tenant_member_attribute = member tenant_name_attribute = ou tenant_desc_attribute = description tenant_enabled_attribute = extensionName tenant_attribute_ignore = role_objectclass = organizationalRole role_id_attribute = cn role_name_attribute = ou role_member_attribute = roleOccupant role_attribute_ignore =............