Keystone 是 OpenStack 的身份认证服务,提供统一的身份验证、授权和服务发现功能。它是 OpenStack 生态系统的核心组件,所有其他服务都依赖它进行身份验证。
1. Keystone 架构概述
1.1 核心架构图
┌─────────────────────────────────────────────────────────────────┐
│ Keystone Architecture │
├─────────────────────────────────────────────────────────────────┤
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Client │ │ Horizon │ │ CLI │ │
│ │Applications │ │ Dashboard │ │ Tools │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │ │ │ │
│ └───────────────────┼───────────────────┘ │
│ │ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ Keystone API (WSGI) │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ Identity API│ │Assignment API│ │Catalog API │ │ │
│ │ │ (v3) │ │ (v3) │ │ (v3) │ │ │
│ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ Core Services │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ Identity │ │ Assignment │ │ Catalog │ │ │
│ │ │ Service │ │ Service │ │ Service │ │ │
│ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ Token │ │ Policy │ │ Trust │ │ │
│ │ │ Service │ │ Service │ │ Service │ │ │
│ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ Backends │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ SQL DB │ │ LDAP │ │ External │ │ │
│ │ │ (MySQL) │ │ Directory │ │ Systems │ │ │
│ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │
│ └─────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
1.2 核心概念
# keystone/server/wsgi.py
def initialize_application():
"""初始化 Keystone WSGI 应用"""
# 加载配置
config.configure()
# 初始化各种服务
services = [
'identity', # 身份服务
'assignment', # 分配服务
'catalog', # 服务目录
'token', # 令牌服务
'policy', # 策略服务
'trust', # 信任服务
'credential', # 凭证服务
]
# 创建 WSGI 应用
application = keystone_service.loadapp('config:keystone.conf')
return application
2. 核心概念和模型
2.1 身份 (Identity) 模型
2.1.1 用户 (User)
# keystone/identity/backends/sql.py
class User(sql.ModelBase, sql.ModelDictMixin):
"""用户模型"""
__tablename__ = 'user'
id = sql.Column(sql.String(64), primary_key=True)
name = sql.Column(sql.String(255), nullable=False)
domain_id = sql.Column(sql.String(64), sql.ForeignKey('domain.id'),
nullable=False)
password = sql.Column(sql.String(128))
enabled = sql.Column(sql.Boolean, default=True)
# 额外属性
default_project_id = sql.Column(sql.String(64))
description = sql.Column(sql.Text())
# 密码过期
password_expires_at = sql.Column(sql.DateTimeInt())
# 多因子认证
multi_factor_auth_enabled = sql.Column(sql.Boolean, default=False)
multi_factor_auth_rules = sql.Column(sql.JsonBlob())
用户操作示例:
# 创建域
openstack domain create --description "Company Domain" company
# 创建用户
openstack user create \
--domain company \
--description "John Doe" \
--email john@company.com \
--password secretpass \
john
# 列出用户
openstack user list --domain company
# 更新用户
openstack user set \
--email newemail@company.com \
--enable \
john
# 设置用户密码
openstack user set --password newpassword john
2.1.2 组 (Group)
# keystone/identity/backends/sql.py
class Group(sql.ModelBase, sql.ModelDictMixin):
"""组模型"""
__tablename__ = 'group'
id = sql.Column(sql.String(64), primary_key=True)
name = sql.Column(sql.String(255), nullable=False)
domain_id = sql.Column(sql.String(64), sql.ForeignKey('domain.id'),
nullable=False)
description = sql.Column(sql.Text())
# 组成员关系
users = relationship('User', secondary='user_group_membership')
class UserGroupMembership(sql.ModelBase, sql.ModelDictMixin):
"""用户组成员关系"""
__tablename__ = 'user_group_membership'
user_id = sql.Column(sql.String(64), sql.ForeignKey('user.id'),
primary_key=True)
group_id = sql.Column(sql.String(64), sql.ForeignKey('group.id'),
primary_key=True)
组操作示例:
# 创建组
openstack group create \
--domain company \
--description "Developers Group" \
developers
# 将用户添加到组
openstack group add user developers john
# 列出组成员
openstack group show developers
# 从组中移除用户
openstack group remove user developers john
2.2 项目和域 (Project & Domain)
2.2.1 域 (Domain)
# keystone/resource/backends/sql.py
class Domain(sql.ModelBase, sql.ModelDictMixin):
"""域模型"""
__tablename__ = 'domain'
id = sql.Column(sql.String(64), primary_key=True)
name = sql.Column(sql.String(255), nullable=False)
enabled = sql.Column(sql.Boolean, default=True, nullable=False)
description = sql.Column(sql.Text())
# 域配置
extra = sql.Column(sql.JsonBlob())
# 关联的项目
projects = relationship('Project', backref='domain')
# 关联的用户
users = relationship('User', backref='domain')
2.2.2 项目 (Project)
# keystone/resource/backends/sql.py
class Project(sql.ModelBase, sql.ModelDictMixin):
"""项目模型"""
__tablename__ = 'project'
id = sql.Column(sql.String(64), primary_key=True)
name = sql.Column(sql.String(255), nullable=False)
domain_id = sql.Column(sql.String(64), sql.ForeignKey('domain.id'),
nullable=False)
description = sql.Column(sql.Text())
enabled = sql.Column(sql.Boolean, default=True)
# 父项目支持 (项目层次结构)
parent_id = sql.Column(sql.String(64), sql.ForeignKey('project.id'))
is_domain = sql.Column(sql.Boolean, default=False)
# 项目标签
tags = sql.Column(sql.JsonBlob())
# 项目选项
options = sql.Column(sql.JsonBlob())
项目操作示例:
# 创建项目
openstack project create \
--domain company \
--description "Development Project" \
--enable \
dev-project
# 创建子项目
openstack project create \
--domain company \
--parent dev-project \
--description "Frontend Development" \
frontend-dev
# 列出项目
openstack project list --domain company
# 显示项目层次结构
openstack project show dev-project --parents
openstack project show dev-project --children
2.3 角色和分配 (Role & Assignment)
2.3.1 角色 (Role)
# keystone/assignment/backends/sql.py
class Role(sql.ModelBase, sql.ModelDictMixin):
"""角色模型"""
__tablename__ = 'role'
id = sql.Column(sql.String(64), primary_key=True)
name = sql.Column(sql.String(255), nullable=False, unique=True)
domain_id = sql.Column(sql.String(64), sql.ForeignKey('domain.id'))
description = sql.Column(sql.Text())
# 角色选项
options = sql.Column(sql.JsonBlob())
class Assignment(sql.ModelBase, sql.ModelDictMixin):
"""角色分配模型"""
__tablename__ = 'assignment'
type = sql.Column(sql.Enum(AssignmentType.USER_PROJECT,
AssignmentType.GROUP_PROJECT,
AssignmentType.USER_DOMAIN,
AssignmentType.GROUP_DOMAIN),
nullable=False)
actor_id = sql.Column(sql.String(64), nullable=False) # 用户或组ID
target_id = sql.Column(sql.String(64), nullable=False) # 项目或域ID
role_id = sql.Column(sql.String(64), sql.ForeignKey('role.id'),
nullable=False)
inherited = sql.Column(sql.Boolean, default=False)
角色分配示例:
# 创建角色
openstack role create developer
openstack role create project-manager
# 在项目中分配角色给用户
openstack role add \
--project dev-project \
--user john \
developer
# 在域中分配角色给组
openstack role add \
--domain company \
--group developers \
member
# 列出角色分配
openstack role assignment list \
--user john \
--project dev-project
# 继承角色分配
openstack role add \
--project parent-project \
--user john \
--inherited \
admin
3. 令牌 (Token) 系统
3.1 令牌类型
# keystone/token/providers/base.py
class Provider(object):
"""令牌提供者基类"""
def issue_token(self, user_id, method_names, expires_at=None,
project_id=None, domain_id=None, auth_context=None,
trust_id=None, include_catalog=True,
parent_audit_id=None):
"""签发令牌"""
# 构建令牌数据
token_data = self._get_token_data(
user_id=user_id,
method_names=method_names,
expires_at=expires_at,
project_id=project_id,
domain_id=domain_id,
auth_context=auth_context,
trust_id=trust_id,
include_catalog=include_catalog
)
# 生成令牌ID
token_id = self._generate_token_id(token_data)
return token_id, token_data
# keystone/token/providers/fernet/core.py
class Provider(base.Provider):
"""Fernet 令牌提供者"""
def __init__(self, *args, **kwargs):
super(Provider, self).__init__(*args, **kwargs)
self.token_formatter = TokenFormatter()
def _generate_token_id(self, token_data):
"""生成 Fernet 令牌ID"""
# 提取关键信息
user_id = token_data['token']['user']['id']
expires_at = token_data['token']['expires_at']
audit_ids = token_data['token']['audit_ids']
# 创建令牌载荷
payload = (user_id, expires_at, audit_ids)
# 使用 Fernet 加密
versioned_payload = (payload, self.token_formatter.creation_time)
token_id = self.token_formatter.pack(versioned_payload)
return token_id
def validate_token(self, token_id):
"""验证令牌"""
try:
# 解密令牌
payload, creation_time = self.token_formatter.unpack(token_id)
user_id, expires_at, audit_ids = payload
# 检查过期时间
if expires_at and expires_at < timeutils.utcnow():
raise exception.TokenNotFound(token_id=token_id)
# 重建令牌数据
return self._rebuild_token_data(user_id, expires_at, audit_ids)
except (ValueError, fernet.InvalidToken):
raise exception.TokenNotFound(token_id=token_id)
3.2 令牌生命周期
# keystone/token/core.py
class Manager(object):
"""令牌管理器"""
def authenticate(self, auth=None):
"""认证并签发令牌"""
# 验证认证方法
method_names = auth.get('identity', {}).keys()
# 执行认证
user_info = self._authenticate(auth)
user_id = user_info['user_id']
# 获取作用域信息
project_id = None
domain_id = None
if 'scope' in auth:
if 'project' in auth['scope']:
project_id = auth['scope']['project']['id']
elif 'domain' in auth['scope']:
domain_id = auth['scope']['domain']['id']
# 设置过期时间
expires_at = self._get_token_expiry_time(
method_names=method_names,
project_id=project_id,
domain_id=domain_id
)
# 签发令牌
token_id, token_data = self.provider.issue_token(
user_id=user_id,
method_names=method_names,
expires_at=expires_at,
project_id=project_id,
domain_id=domain_id,
include_catalog=True
)
return token_id, token_data
def revoke_token(self, token_id, revoke_chain=False):
"""撤销令牌"""
# 记录撤销事件
revoke_event = {
'token_id': token_id,
'revoked_at': timeutils.utcnow(),
'user_id': token_data['token']['user']['id']
}
if revoke_chain:
# 撤销整个令牌链
self._revoke_token_chain(token_id)
# 添加到撤销列表
self.revoke_api.revoke_by_event(revoke_event)
4. 服务目录 (Service Catalog)
4.1 服务和端点模型
# keystone/catalog/backends/sql.py
class Service(sql.ModelBase, sql.ModelDictMixin):
"""服务模型"""
__tablename__ = 'service'
id = sql.Column(sql.String(64), primary_key=True)
type = sql.Column(sql.String(255), nullable=False) # compute, network, etc.
name = sql.Column(sql.String(255), nullable=False)
description = sql.Column(sql.Text())
enabled = sql.Column(sql.Boolean, default=True)
# 关联的端点
endpoints = relationship('Endpoint', backref='service')
class Endpoint(sql.ModelBase, sql.ModelDictMixin):
"""端点模型"""
__tablename__ = 'endpoint'
id = sql.Column(sql.String(64), primary_key=True)
service_id = sql.Column(sql.String(64), sql.ForeignKey('service.id'),
nullable=False)
interface = sql.Column(sql.Enum('public', 'internal', 'admin'),
nullable=False)
url = sql.Column(sql.Text(), nullable=False)
region_id = sql.Column(sql.String(255))
enabled = sql.Column(sql.Boolean, default=True)
class Region(sql.ModelBase, sql.ModelDictMixin):
"""区域模型"""
__tablename__ = 'region'
id = sql.Column(sql.String(255), primary_key=True)
description = sql.Column(sql.String(255))
parent_region_id = sql.Column(sql.String(255), sql.ForeignKey('region.id'))
# 区域层次结构
sub_regions = relationship('Region')
4.2 服务目录操作
# 创建服务
openstack service create \
--name nova \
--description "OpenStack Compute Service" \
compute
openstack service create \
--name neutron \
--description "OpenStack Networking Service" \
network
# 创建端点
openstack endpoint create \
--region RegionOne \
compute public http://controller:8774/v2.1
openstack endpoint create \
--region RegionOne \
compute internal http://controller:8774/v2.1
openstack endpoint create \
--region RegionOne \
compute admin http://controller:8774/v2.1
# 列出服务目录
openstack catalog list
openstack catalog show compute
# 查看令牌包含的服务目录
openstack token issue
5. 认证机制
5.1 密码认证
# keystone/auth/plugins/password.py
class Password(base.AuthMethodHandler):
"""密码认证插件"""
method = 'password'
def authenticate(self, auth_payload):
"""执行密码认证"""
response_data = {}
# 提取用户信息
user_info = auth_payload['user']
user_id = user_info.get('id')
user_name = user_info.get('name')
domain_info = user_info.get('domain', {})
password = user_info['password']
# 获取用户对象
if user_id:
user_ref = PROVIDERS.identity_api.get_user(user_id)
else:
domain_id = self._lookup_domain(domain_info)
user_ref = PROVIDERS.identity_api.get_user_by_name(
user_name, domain_id)
# 验证密码
PROVIDERS.identity_api.authenticate(
user_id=user_ref['id'],
password=password)
response_data['user_id'] = user_ref['id']
return base.AuthHandlerResponse(
status=True,
response_body=None,
response_data=response_data)
5.2 令牌认证
# keystone/auth/plugins/token.py
class Token(base.AuthMethodHandler):
"""令牌认证插件"""
method = 'token'
def authenticate(self, auth_payload):
"""执行令牌认证"""
response_data = {}
# 获取令牌ID
token_id = auth_payload['id']
# 验证令牌
token_data = PROVIDERS.token_provider_api.validate_token(token_id)
# 提取用户信息
user_id = token_data['token']['user']['id']
response_data['user_id'] = user_id
response_data['auth_token'] = token_data
return base.AuthHandlerResponse(
status=True,
response_body=None,
response_data=response_data)
5.3 多因子认证 (MFA)
# keystone/auth/plugins/totp.py
class TOTP(base.AuthMethodHandler):
"""TOTP (时间戳动态密码) 认证插件"""
method = 'totp'
def authenticate(self, auth_payload):
"""执行 TOTP 认证"""
response_data = {}
# 获取用户信息
user_info = auth_payload['user']
user_id = user_info['id']
passcode = auth_payload['passcode']
# 获取用户的 TOTP 凭证
credential_list = PROVIDERS.credential_api.list_credentials_for_user(
user_id, type='totp')
if not credential_list:
raise exception.Unauthorized('No TOTP credentials found')
# 验证 TOTP 代码
for credential in credential_list:
if self._validate_totp_passcode(credential, passcode):
response_data['user_id'] = user_id
return base.AuthHandlerResponse(
status=True,
response_body=None,
response_data=response_data)
raise exception.Unauthorized('Invalid TOTP passcode')
def _validate_totp_passcode(self, credential, passcode):
"""验证 TOTP 密码"""
import pyotp
secret = credential['blob']
totp = pyotp.TOTP(secret)
# 允许时间窗口偏差
return totp.verify(passcode, valid_window=1)
6. 策略 (Policy) 系统
6.1 策略引擎
# keystone/policy/backends/rules.py
class Rules(base.PolicyDriverBase):
"""基于规则的策略驱动"""
def __init__(self):
super(Rules, self).__init__()
self.enforcer = policy.Enforcer(CONF)
def enforce(self, credentials, action, target):
"""执行策略检查"""
# 构建上下文
context = {
'user_id': credentials.get('user_id'),
'project_id': credentials.get('project_id'),
'domain_id': credentials.get('domain_id'),
'roles': credentials.get('roles', []),
'is_admin': credentials.get('is_admin', False),
}
# 执行策略检查
try:
self.enforcer.enforce(action, target, context,
do_raise=True,
exc=exception.ForbiddenAction,
action=action)
except policy.PolicyNotAuthorized:
raise exception.Forbidden(action=action)
# keystone/common/policies/base.py
def build_enforcement_kwargs(func):
"""构建策略执行参数的装饰器"""
def wrapper(self, request, *args, **kwargs):
context = request.context
target = {}
# 从请求中提取目标信息
if hasattr(request, 'context_dict'):
target.update(request.context_dict)
# 执行策略检查
self.policy_api.enforce(
context.auth_context,
action=func.__name__,
target=target)
return func(self, request, *args, **kwargs)
return wrapper
6.2 策略配置示例
# /etc/keystone/policy.yaml
"admin_required": "role:admin"
"service_role": "role:service"
"service_or_admin": "rule:admin_required or rule:service_role"
"owner": "user_id:%(user_id)s"
"admin_or_owner": "rule:admin_required or rule:owner"
"token_subject": "user_id:%(target.token.user_id)s"
"admin_or_token_subject": "rule:admin_required or rule:token_subject"
# Identity API
"identity:get_user": "rule:admin_or_owner"
"identity:list_users": "rule:admin_required"
"identity:create_user": "rule:admin_required"
"identity:update_user": "rule:admin_required"
"identity:delete_user": "rule:admin_required"
"identity:get_group": "rule:admin_required"
"identity:list_groups": "rule:admin_required"
"identity:create_group": "rule:admin_required"
"identity:update_group": "rule:admin_required"
"identity:delete_group": "rule:admin_required"
# Resource API
"resource:get_project": "rule:admin_required or project_id:%(target.project.id)s"
"resource:list_projects": "rule:admin_required"
"resource:create_project": "rule:admin_required"
"resource:update_project": "rule:admin_required"
"resource:delete_project": "rule:admin_required"
# Assignment API
"assignment:list_role_assignments": "rule:admin_required"
"assignment:create_grant": "rule:admin_required"
"assignment:check_grant": "rule:admin_required"
"assignment:revoke_grant": "rule:admin_required"
7. 联邦认证 (Federation)
7.1 身份提供者 (Identity Provider)
# keystone/federation/backends/sql.py
class IdentityProvider(sql.ModelBase, sql.ModelDictMixin):
"""身份提供者模型"""
__tablename__ = 'identity_provider'
id = sql.Column(sql.String(64), primary_key=True)
description = sql.Column(sql.Text())
enabled = sql.Column(sql.Boolean, nullable=False)
remote_ids = sql.Column(sql.JsonBlob(), nullable=False)
# 域ID
domain_id = sql.Column(sql.String(64), sql.ForeignKey('domain.id'))
class FederationProtocol(sql.ModelBase, sql.ModelDictMixin):
"""联邦协议模型"""
__tablename__ = 'federation_protocol'
id = sql.Column(sql.String(64), primary_key=True)
idp_id = sql.Column(sql.String(64), sql.ForeignKey('identity_provider.id'),
primary_key=True)
mapping_id = sql.Column(sql.String(64), sql.ForeignKey('mapping.id'),
nullable=False)
7.2 映射规则
# keystone/federation/backends/sql.py
class Mapping(sql.ModelBase, sql.ModelDictMixin):
"""映射模型"""
__tablename__ = 'mapping'
id = sql.Column(sql.String(64), primary_key=True)
rules = sql.Column(sql.JsonBlob(), nullable=False)
# 映射规则示例
mapping_rules = [
{
"local": [
{
"user": {
"name": "{0}",
"domain": {
"name": "federated_domain"
}
}
},
{
"group": {
"name": "federated_users",
"domain": {
"name": "federated_domain"
}
}
}
],
"remote": [
{
"type": "REMOTE_USER"
},
{
"type": "HTTP_SHIB_IDENTITY_PROVIDER",
"any_one_of": ["university_idp"]
}
]
}
]
7.3 SAML 配置
# 创建身份提供者
openstack identity provider create \
--description "University SAML IdP" \
--remote-id https://university.edu/saml/metadata \
university_idp
# 创建映射
openstack mapping create \
--rules mapping_rules.json \
university_mapping
# 创建协议
openstack federation protocol create \
--identity-provider university_idp \
--mapping university_mapping \
saml2
# 配置 Apache mod_shib
# /etc/httpd/conf.d/keystone.conf
<Location /Shibboleth.sso>
SetHandler shib
</Location>
<Location /v3/OS-FEDERATION/identity_providers/university_idp/protocols/saml2/auth>
ShibRequestSetting requireSession 1
AuthType shibboleth
ShibExportAssertion Off
Require valid-user
</Location>
8. 配置和部署
8.1 主配置文件
# /etc/keystone/keystone.conf
[DEFAULT]
# 日志配置
debug = False
verbose = True
log_file = /var/log/keystone/keystone.log
# 数据库连接
[database]
connection = mysql+pymysql://keystone:password@controller/keystone
connection_recycle_time = 10
max_pool_size = 1
max_retries = -1
# 令牌配置
[token]
provider = fernet
expiration = 3600
revoke_by_id = False
# Fernet 令牌配置
[fernet_tokens]
key_repository = /etc/keystone/fernet-keys/
max_active_keys = 3
# 缓存配置
[cache]
enabled = True
backend = oslo_cache.memcache_pool
memcache_servers = controller:11211
# 认证配置
[auth]
methods = external,password,token,oauth1,mapped,application_credential
password = keystone.auth.plugins.password.Password
token = keystone.auth.plugins.token.Token
# 身份后端
[identity]
driver = keystone.identity.backends.sql.Identity
default_domain_id = default
# 分配后端
[assignment]
driver = keystone.assignment.backends.sql.Assignment
# 资源后端
[resource]
driver = keystone.resource.backends.sql.Resource
# 角色后端
[role]
driver = keystone.assignment.backends.sql.Role
# 服务目录后端
[catalog]
driver = keystone.catalog.backends.sql.Catalog
# 策略后端
[policy]
driver = keystone.policy.backends.sql.Policy
# 信任后端
[trust]
driver = keystone.trust.backends.sql.Trust
enabled = True
allow_redelegation = False
max_redelegation_count = 3
# 联邦认证
[federation]
driver = keystone.federation.backends.sql.Federation
8.2 WSGI 配置
# /etc/httpd/conf.d/wsgi-keystone.conf
Listen 5000
Listen 35357
<VirtualHost *:5000>
WSGIDaemonProcess keystone-public processes=5 threads=1 user=keystone group=keystone display-name=%{GROUP}
WSGIProcessGroup keystone-public
WSGIScriptAlias / /usr/bin/keystone-wsgi-public
WSGIApplicationGroup %{GLOBAL}
WSGIPassAuthorization On
LimitRequestBody 114688
<IfVersion >= 2.4>
ErrorLogFormat "%{cu}t %M"
</IfVersion>
ErrorLog /var/log/httpd/keystone.log
CustomLog /var/log/httpd/keystone_access.log combined
<Directory /usr/bin>
<IfVersion >= 2.4>
Require all granted
</IfVersion>
<IfVersion < 2.4>
Order allow,deny
Allow from all
</IfVersion>
</Directory>
</VirtualHost>
<VirtualHost *:35357>
WSGIDaemonProcess keystone-admin processes=5 threads=1 user=keystone group=keystone display-name=%{GROUP}
WSGIProcessGroup keystone-admin
WSGIScriptAlias / /usr/bin/keystone-wsgi-admin
WSGIApplicationGroup %{GLOBAL}
WSGIPassAuthorization On
LimitRequestBody 114688
ErrorLog /var/log/httpd/keystone.log
CustomLog /var/log/httpd/keystone_access.log combined
<Directory /usr/bin>
<IfVersion >= 2.4>
Require all granted
</IfVersion>
<IfVersion < 2.4>
Order allow,deny
Allow from all
</IfVersion>
</Directory>
</VirtualHost>
9. 高可用和性能优化
9.1 高可用部署
# HAProxy 配置
# /etc/haproxy/haproxy.cfg
global
chroot /var/lib/haproxy
stats socket /run/haproxy/admin.sock mode 660 level admin
stats timeout 30s
user haproxy
group haproxy
daemon
defaults
mode http
timeout connect 5000ms
timeout client 50000ms
timeout server 50000ms
frontend keystone_public
bind *:5000
default_backend keystone_public_servers
frontend keystone_admin
bind *:35357
default_backend keystone_admin_servers
backend keystone_public_servers
balance roundrobin
option httpchk GET /v3
server controller1 10.0.1.11:5000 check
server controller2 10.0.1.12:5000 check
server controller3 10.0.1.13:5000 check
backend keystone_admin_servers
balance roundrobin
option httpchk GET /v3
server controller1 10.0.1.11:35357 check
server controller2 10.0.1.12:35357 check
server controller3 10.0.1.13:35357 check
9.2 性能调优
# 数据库连接池优化
[database]
connection = mysql+pymysql://keystone:password@controller/keystone
max_pool_size = 20
max_overflow = 30
pool_timeout = 30
pool_recycle = 300
# 缓存优化
[cache]
enabled = True
backend = oslo_cache.memcache_pool
memcache_servers = controller1:11211,controller2:11211,controller3:11211
expiration_time = 600
# 令牌优化
[token]
provider = fernet
expiration = 3600
cache_time = 300
# WSGI 进程优化
# WSGIDaemonProcess keystone-public processes=10 threads=5
10. 监控和故障排除
10.1 健康检查
# keystone/common/health.py
class HealthController(flask_restful.Resource):
"""健康检查控制器"""
def get(self):
"""获取健康状态"""
status = {
'status': 'UP',
'components': {}
}
# 检查数据库连接
try:
PROVIDERS.identity_api.list_users()
status['components']['database'] = {'status': 'UP'}
except Exception as e:
status['components']['database'] = {
'status': 'DOWN',
'error': str(e)
}
status['status'] = 'DOWN'
# 检查缓存
try:
cache.get_cache_region().get('health_check')
status['components']['cache'] = {'status': 'UP'}
except Exception as e:
status['components']['cache'] = {
'status': 'DOWN',
'error': str(e)
}
return status
10.2 日志分析
# 查看认证失败
grep "UNAUTHORIZED" /var/log/keystone/keystone.log
# 查看令牌操作
grep "token" /var/log/keystone/keystone.log | grep -E "(issue|validate|revoke)"
# 查看数据库连接问题
grep "Lost connection" /var/log/keystone/keystone.log
# 查看性能问题
grep "Slow query" /var/log/keystone/keystone.log
# 实时监控
tail -f /var/log/keystone/keystone.log | grep -E "(ERROR|WARNING)"
10.3 性能监控
# 自定义监控脚本
#!/usr/bin/env python3
import time
import requests
import json
def check_keystone_performance():
"""检查 Keystone 性能"""
auth_data = {
"auth": {
"identity": {
"methods": ["password"],
"password": {
"user": {
"name": "admin",
"domain": {"name": "Default"},
"password": "password"
}
}
},
"scope": {
"project": {
"name": "admin",
"domain": {"name": "Default"}
}
}
}
}
# 测试认证性能
start_time = time.time()
response = requests.post(
'http://controller:5000/v3/auth/tokens',
json=auth_data,
headers={'Content-Type': 'application/json'}
)
auth_time = time.time() - start_time
if response.status_code == 201:
token = response.headers['X-Subject-Token']
# 测试令牌验证性能
start_time = time.time()
validate_response = requests.get(
'http://controller:5000/v3/auth/tokens',
headers={
'X-Auth-Token': token,
'X-Subject-Token': token
}
)
validate_time = time.time() - start_time
print(f"Auth time: {auth_time:.3f}s")
print(f"Validate time: {validate_time:.3f}s")
# 警告阈值
if auth_time > 2.0:
print("WARNING: Authentication is slow!")
if validate_time > 1.0:
print("WARNING: Token validation is slow!")
else:
print(f"Authentication failed: {response.status_code}")
if __name__ == '__main__':
check_keystone_performance()
11. 安全最佳实践
11.1 密码策略
# /etc/keystone/keystone.conf
[security_compliance]
# 密码强度要求
password_regex = ^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%^&+=]).{8,}$
password_regex_description = Password must contain at least 8 characters including one lowercase letter, one uppercase letter, one digit, and one special character
# 密码历史
unique_last_password_count = 5
# 密码过期
password_expires_days = 90
password_expire_warn_days = 30
# 账户锁定
lockout_failure_attempts = 5
lockout_duration = 300
# 会话管理
minimum_password_age = 1
change_password_upon_first_use = True
11.2 令牌安全
# Fernet 密钥轮换
keystone-manage fernet_setup --keystone-user keystone --keystone-group keystone
keystone-manage fernet_rotate --keystone-user keystone --keystone-group keystone
# 定期轮换脚本
#!/bin/bash
# /usr/local/bin/rotate_fernet_keys.sh
# 备份当前密钥
cp -r /etc/keystone/fernet-keys /etc/keystone/fernet-keys.backup.$(date +%Y%m%d)
# 轮换密钥
keystone-manage fernet_rotate --keystone-user keystone --keystone-group keystone
# 重启服务
systemctl reload httpd
# 验证
sleep 5
curl -s http://controller:5000/v3 > /dev/null && echo "Keystone is healthy after key rotation"
# 添加到 crontab
# 0 2 * * 0 /usr/local/bin/rotate_fernet_keys.sh
11.3 审计日志
# /etc/keystone/keystone.conf
[audit]
enabled = True
audit_map_file = /etc/keystone/api_audit_map.conf
# /etc/keystone/api_audit_map.conf
[resource_type_map]
users = user
projects = project
groups = group
domains = domain
roles = role
[path_keyword_map]
users = user_id
projects = project_id
groups = group_id
domains = domain_id
roles = role_id
[service_endpoints]
identity = /v3/users, /v3/projects, /v3/groups, /v3/domains, /v3/roles
总结
Keystone 作为 OpenStack 的身份认证服务,提供了:
核心功能:
- 身份管理:用户、组、域的生命周期管理
- 认证服务:多种认证方法支持
- 授权管理:基于角色的访问控制
- 服务发现:统一的服务目录
- 令牌管理:安全的令牌签发和验证
架构优势:
- 模块化设计:可插拔的后端驱动
- 可扩展性:支持联邦认证和外部身份源
- 高可用性:无状态设计,易于水平扩展
- 安全性:Fernet 令牌,策略引擎,审计日志
部署考虑:
- 性能优化:合理配置缓存和数据库连接池
- 安全加固:密码策略、密钥轮换、审计日志
- 高可用部署:负载均衡、数据库集群
- 监控运维:健康检查、性能监控、日志分析
Keystone 是构建安全、可靠的 OpenStack 云平台的基础,正确的配置和运维对整个云平台的安全性和稳定性至关重要。
Similar code found with 3 license types