OpenStack Keystone手动安装与配置实战指南 1. 项目概述这不是一次普通的服务部署而是一次对 OpenStack 身份认证体系的“解剖式”实操Keystone 是 OpenStack 的核心服务之一它不直接处理计算、存储或网络资源却像城市交通指挥中心一样掌控着所有用户、角色、项目、服务和端点的访问权限。你无法绕过它去启动一台虚拟机也无法跳过它去创建一个对象存储容器——它就是整个云平台的“门禁系统”与“身份档案馆”。标题里写的“6.2 实训项目3 Keystone 的手动安装与配置”表面看是教学大纲里的一个编号任务但背后藏着的是对云基础设施底层逻辑的一次真实触达。我带过十几期 OpenStack 运维实训班发现一个普遍现象90% 的学员能用自动化脚本一键部署全套 OpenStack但一旦 Keystone 报错“Invalid token”或“Service not found”立刻陷入茫然。为什么因为脚本把所有依赖、证书、数据库初始化、服务注册这些“脏活累活”全包圆了你只看到一个绿色的 SUCCESS却不知道绿色背后哪一行 SQL 插入失败、哪个环境变量漏写了、哪条 endpoint URL 少了个斜杠。这次手动安装就是要亲手拧紧每一颗螺丝——从 MySQL 创建 keystone 数据库开始到生成 Fernet 密钥、初始化数据库表结构、配置 Apache 模块、注册 admin 用户与 service project再到最后用 curl 验证 token 获取是否成功。它适合三类人正在备考 OpenStack 认证如 COA的工程师、需要在生产环境中做 Keystone 故障深度排查的运维人员以及想真正理解“为什么 OpenStack 必须先配 Keystone”的云计算初学者。你不需要提前掌握 Python 编程但必须熟悉 Linux 基础命令、HTTP 状态码含义、以及如何阅读日志文件。这不是教你怎么“点下一步”而是带你回到 2012 年 OpenStack 社区刚起步时开发者们最原始、最扎实的部署方式。2. 整体设计思路与方案选型解析为什么坚持“手动”而不是用 DevStack 或 Kolla2.1 手动安装不是复古情怀而是为了暴露关键决策点很多人看到“手动安装”第一反应是“太老土了现在谁还这么干”这种看法恰恰暴露了对云平台本质理解的偏差。DevStack 是个极好的开发测试工具但它把所有服务都塞进一个本地用户目录下用 screen 启一堆进程数据库用 SQLite证书全自签且路径混乱Kolla 则是面向生产环境的容器化部署但它的抽象层级太高——你改一个 keystone.conf 变量得先理解 kolla-ansible 的 role 结构、jinja2 模板继承关系、以及 Ansible 的 facts 注入机制。而手动安装是唯一一种能让你在每一步都停下来问“为什么必须这样”的方式。比如为什么 Keystone 默认用 Apache mod_wsgi 而不是自带的 eventlet 服务器因为 eventlet 是单线程异步模型在高并发 token 校验场景下容易成为瓶颈而 Apache 的 prefork 或 worker 模型能更好利用多核 CPU为什么数据库表初始化要用 keystone-manage db_sync 而不是直接执行 SQL 脚本因为 Keystone 的 migration 机制是基于 Alembic 的它会自动记录当前数据库版本并在升级时只执行增量变更避免手动 SQL 漏掉某张审计表为什么 Fernet 密钥要分组管理key_repository且必须设置轮转策略因为 Fernet 是对称加密密钥一旦泄露所有已签发的 token 都可被伪造而轮转机制确保旧密钥只用于解密历史 token新 token 全部用新密钥签名形成时间隔离。这些不是文档里一句带过的“最佳实践”而是你在手动执行keystone-manage fernet_setup --keystone-user keystone --keystone-group keystone这条命令时必须思考的底层逻辑。2.2 环境选型Ubuntu 22.04 LTS MySQL 8.0 Apache 2.4 是当前最稳妥的组合我们不选 CentOS Stream 或 Rocky Linux是因为 Ubuntu 22.04 的 APT 源对 OpenStack Yoga/Zed 版本支持最成熟Python 3.10 环境开箱即用且社区文档覆盖最全。MySQL 8.0 是硬性要求——Keystone 从 Queens 版本起就废弃了对 MySQL 5.7 以下版本的支持主要原因是其 JSON 数据类型和窗口函数被大量用于 policy 规则引擎与审计日志分析。你可能会看到网上有教程用 SQLite 做演示那纯粹是教学简化生产环境绝对禁止SQLite 是文件级锁当多个服务如 Nova、Cinder同时向 Keystone 请求 token 时会因锁竞争导致严重延迟。Apache 2.4 也是经过验证的选择它比 Nginx 更早原生支持 WSGI 协议mod_wsgi 模块与 Keystone 的集成度更高错误日志中能直接打印出 Python traceback这对排错至关重要。至于 Python 版本OpenStack 官方已全面转向 Python 3Python 2.7 在 2020 年就停止维护任何还在用 py2 的教程都是过期信息。我们不会去折腾源码编译而是严格使用 Ubuntu 官方仓库提供的 python3-keystone 包因为它已经过 Canonical 工程师的兼容性测试避免了 pip install keystonexx 可能引入的依赖冲突比如某个旧版 oslo.config 与新版本不兼容。2.3 架构精简只部署 Keystone 核心组件剥离无关服务干扰这个实训项目明确限定为“Keystone 的手动安装与配置”因此我们必须主动做减法。不安装 Glance镜像服务、不部署 Nova计算服务、不配置 HorizonWeb 控制台。很多初学者一上来就想搭个“完整云”结果 Keystone 还没跑通就被 Glance 的 registry 服务报错拖垮了注意力。我们要构建一个最小可行环境MVP仅包含 MySQL数据存储、ApacheWeb 服务器、KeystoneWSGI 应用、以及用于验证的 curl 和 openstack client。所有服务都运行在同一台物理机或虚拟机上IP 地址固定为 192.168.100.10这个地址会在后续配置中反复出现务必记牢。这种“单点聚焦”不是偷懒而是工程思维的体现——当你连最简单的单节点 Keystone 都无法稳定运行时加再多节点也只会放大问题。就像修车师傅不会一边换火花塞一边调刹车片我们必须把身份认证这条链路彻底跑通再考虑与其他服务对接。3. 核心细节解析与实操要点从系统准备到服务启动的 12 个关键动作3.1 系统初始化时间同步、防火墙与主机名是隐形地雷在敲下第一条 apt 命令前有三件事必须做完它们不出现在任何 Keystone 官方文档的“第一步”却是我踩过最多坑的环节。第一是时间同步。OpenStack 对时间精度要求极高所有服务间的 token 签名都带时间戳如果 Keystone 服务器与客户端时间相差超过 5 分钟token 会被直接拒绝。不要用 systemd-timesyncd 这种轻量级服务它默认只做单向时间校准稳定性不足。必须安装 chronysudo apt install chrony -y然后编辑/etc/chrony/chrony.conf注释掉所有 pool 行添加server ntp.aliyun.com iburst阿里云 NTP 服务器在国内延迟低、可用性高最后重启服务sudo systemctl restart chrony。第二是防火墙。Ubuntu 默认启用 ufw它会拦截 5000 端口Keystone 默认 API 端口。很多人部署完发现 curl http://192.168.100.10:5000/v3 失败查半天以为是 Apache 没配好其实是 ufw 在作祟。执行sudo ufw allow 5000即可放行。第三是主机名解析。Keystone 内部服务注册、endpoint URL 生成都依赖主机名。必须确保hostname -f返回的是一个完整的 FQDN如 controller.example.com而不是单纯的 controller。编辑/etc/hosts添加一行192.168.100.10 controller.example.com controller然后执行sudo hostnamectl set-hostname controller.example.com。这三步看似琐碎但任何一个遗漏都会导致后续步骤中出现“Connection refused”、“Invalid endpoint”等让人抓狂的错误而且日志里找不到直接线索。3.2 数据库准备MySQL 8.0 的密码策略与字符集是两大陷阱Keystone 需要一个独立的数据库来存储用户、角色、项目等元数据。创建过程远不止CREATE DATABASE keystone;这么简单。首先MySQL 8.0 默认启用了caching_sha2_password认证插件而 Keystone 的 Python MySQL 驱动PyMySQL在较老版本中不支持它会导致连接数据库时报错Authentication plugin caching_sha2_password cannot be loaded。解决方案是在创建用户时强制指定mysql_native_password插件CREATE USER keystonelocalhost IDENTIFIED WITH mysql_native_password BY KEYSTONE_DBPASS;。其次字符集必须设为 utf8mb4。Keystone 的 user_name、project_name 等字段允许 Unicode 字符比如中文用户名如果数据库用默认的 latin1插入中文时会变成乱码后续用 openstack user list 查看就是一堆问号。所以建库语句必须是CREATE DATABASE keystone CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;。最后授权语句不能只写GRANT ALL PRIVILEGES ON keystone.* TO keystonelocalhost因为 Keystone 服务可能从其他节点比如未来要加的 compute 节点连接数据库所以必须加上远程访问权限GRANT ALL PRIVILEGES ON keystone.* TO keystone% IDENTIFIED WITH mysql_native_password BY KEYSTONE_DBPASS;。执行完别忘了FLUSH PRIVILEGES;。这三处细节网上 70% 的 MySQL 安装教程都会漏掉其中至少一项导致 Keystone 启动后日志里疯狂刷pymysql.err.OperationalError: (1045, Access denied for user...)。3.3 用户与组创建系统级隔离是安全基线不是形式主义Keystone 服务进程不应该以 root 用户运行这是最基本的安全原则。我们必须创建一个专用的系统用户和组。执行sudo useradd -r -s /bin/false keystone其中-r表示创建系统用户UID 1000-s /bin/false表示该用户无法登录 shell彻底杜绝了通过该账户提权的可能性。接着创建组sudo groupadd keystone并将用户加入组sudo usermod -a -G keystone keystone。这步的意义远超“按规范办事”。当你后续配置 Apache 的 WSGI 进程时会用到WSGIDaemonProcess指令其中userkeystone groupkeystone参数就依赖于此。如果这里用户不存在Apache 启动会失败错误日志里只显示Permission denied根本看不出是用户问题。更隐蔽的坑在于 Fernet 密钥目录的权限。Keystone 要求密钥文件只能被 keystone 用户读写其他用户不可访问。如果你跳过这步直接用 root 创建/etc/keystone/fernet-keys目录那么keystone-manage fernet_setup命令会成功但 Apache 进程以 www-data 用户运行在尝试读取密钥时会因权限不足而崩溃。所以创建用户和组是为后续所有权限控制打下的第一根桩。3.4 配置文件结构解析keystone.conf 不是参数列表而是一张服务关系图谱/etc/keystone/keystone.conf是 Keystone 的心脏但它的结构常被误解为“一堆 keyvalue 的集合”。实际上它是一个分层的、模块化的配置图谱。最顶层是[DEFAULT]它定义全局行为比如log_dir /var/log/keystone指定了所有日志的根目录transport_url rabbit://openstack:RABBIT_PASScontroller则指向消息队列虽然本实训暂不启用但必须存在否则启动报错。往下是[database]这里填的是刚才创建的 MySQL 连接字符串connection mysqlpymysql://keystone:KEYSTONE_DBPASScontroller/keystone。注意这里的controller是我们之前在/etc/hosts里配置的主机名不是 IP 地址这是为了将来扩展成多节点时方便 DNS 切换。最关键的是[identity]和[assignment]模块。[identity]指定用户、域、组的后端存储默认是sql意味着所有用户信息都存 MySQL[assignment]则管理角色、项目、域分配关系同样用sql。很多人会忽略[token]模块但它决定了 token 的生成方式。我们用provider fernet而不是过时的uuid或pki因为 Fernet 性能高、无需 CA 证书、且支持密钥轮转。而[cache]模块则启用了 memcache 作为 token 缓存backend dogpile.cache.memcached这能极大减轻数据库压力——每次 token 校验先查缓存命中则秒回未命中才查 DB。理解每个 section 的职责比死记硬背参数值重要十倍。3.5 Fernet 密钥初始化不是“运行命令就行”而是理解密钥生命周期Fernet 是 Keystone 的 token 加密标准它要求一组密钥协同工作而非单一密钥。keystone-manage fernet_setup命令会创建两个子目录0/主密钥和1/备用密钥。但很多人不知道0/目录下的密钥文件如0000000000000000000000000000000000000000000000000000000000000000并不是随机生成的而是由keystone-manage fernet_rotate命令根据一个种子seed和轮转计数器动态派生的。这意味着如果你备份了/etc/keystone/fernet-keys目录恢复时必须保证 seed 文件/etc/keystone/fernet-keys/0/0000000000000000000000000000000000000000000000000000000000000000与原始环境完全一致否则所有已签发的 token 都无法解密。所以fernet_setup后的第一件事不是启动服务而是执行sudo chown -R keystone:keystone /etc/keystone/fernet-keys确保只有 keystone 用户能读写。第二件事是立即备份这个目录sudo cp -r /etc/keystone/fernet-keys /root/keystone-fernet-backup-$(date %F)。第三件事是理解轮转机制。keystone-manage fernet_rotate默认会将0/的密钥移到1/并生成新的0/但旧密钥仍保留在1/中用于解密历史 token。生产环境建议每周轮转一次并保留至少 3 个历史密钥通过max_active_keys 3参数配置以防 token 有效期默认 24 小时跨越轮转周期。3.6 Apache 配置WSGI 是桥梁不是装饰每一个参数都有血泪教训Keystone 不是独立 Web 服务它必须寄生在 Apache 下通过 WSGI 协议与之通信。/etc/apache2/sites-available/wsgi-keystone.conf这个文件就是这座桥梁的设计蓝图。WSGIScriptAlias / /usr/bin/keystone-wsgi-admin这行告诉 Apache所有以/开头的请求都交给/usr/bin/keystone-wsgi-admin这个 Python 脚本处理。但关键在后面WSGIDaemonProcess keystone-admin processes5 threads1 userkeystone groupkeystone display-name%{GROUP}。processes5表示启动 5 个独立的 Python 进程每个进程处理一个请求避免单进程阻塞threads1是硬性要求因为 Keystone 的某些内部锁如数据库连接池不是线程安全的开多线程反而会死锁user/group必须与前面创建的系统用户一致。最容易被忽略的是Directory /usr/bin块里的Require all granted它允许 Apache 从任意路径加载 WSGI 脚本。如果没有这一行Apache 会返回 403 Forbidden 错误而日志里只显示client denied by server configuration让人误以为是网络问题。最后启用站点sudo a2ensite wsgi-keystone.conf和sudo a2enmod wsgi是必须的前者激活配置后者加载 WSGI 模块。很多人漏掉a2enmod wsgi结果 Apache 启动成功但访问 5000 端口时返回 503 Service Unavailable查日志才发现Invalid command WSGIScriptAlias—— 因为模块根本没加载。3.7 数据库同步与初始数据注入db_sync 是骨架bootstrap 是血肉keystone-manage db_sync命令的作用是让 Keystone 的数据库模型SQLAlchemy 定义与实际的 MySQL 表结构保持一致。它会自动执行所有未应用的 Alembic migration 脚本创建user,role,project,domain,credential等核心表。但这只是“骨架”没有数据Keystone 就是个空壳。keystone-manage bootstrap才是注入“血肉”的关键。它会一次性完成五件事1) 创建admin用户密码为你指定的ADMIN_PASS2) 创建admin角色3) 创建admin项目也叫 tenant4) 将admin用户在admin项目中赋予admin角色5) 创建service项目用于存放所有 OpenStack 服务如 nova、glance的注册信息。这个命令必须在db_sync之后执行否则会报Table keystone.user doesnt exist。而且bootstrap命令会自动创建admin用户的servicetoken这个 token 存储在/var/keystone/admin-token文件中是后续所有服务注册的“万能钥匙”。所以执行完bootstrap一定要记住这个 token 值或者直接 cat 一下文件因为接下来注册 service 和 endpoint 时它就是你的“身份证”。3.8 服务与端点注册Endpoint 不是 URL而是 Keystone 的“服务地图”OpenStack 的所有服务Nova、Glance、Cinder都必须向 Keystone “报备”这个过程叫 service registration。openstack service create --name keystone --description OpenStack Identity identity这条命令就是在 Keystone 的数据库里插入一条记录表示“这里有一个名为 keystone 的 identity 类型服务”。但光有服务名还不够其他服务怎么找到它这就靠 endpoint端点。openstack endpoint create --region RegionOne identity public http://controller:5000/v3这条命令是在service表和endpoint表之间建立关联并指明在RegionOne这个地理区域identity服务的公开访问地址是http://controller:5000/v3。注意这里有三个关键点第一--region参数必须是RegionOne这是 OpenStack 的默认区域名几乎所有客户端都硬编码了它改了会导致后续所有服务无法通信第二URL 中的controller必须与/etc/hosts里配置的主机名完全一致大小写都不能错第三/v3是 Keystone v3 API 的路径v2 API 已废弃绝不能写成/v2.0。注册完成后你可以用openstack endpoint list查看所有端点输出应该包含public,internal,admin三种接口类型分别对应外部用户、内部服务、管理员的访问入口。对于 Keystone 自身public和admin接口通常指向同一个 URL但internal接口应指向http://127.0.0.1:5000/v3因为内部服务如 Nova与 Keystone 在同一台机器上走 localhost 更高效、更安全。3.9 环境变量与 OpenStack Client 配置OS_* 变量是客户端的“DNA”openstack命令行工具本身不存储任何认证信息它完全依赖环境变量。export OS_AUTH_URLhttp://controller:5000/v3这行告诉客户端“我的 Keystone 服务在哪儿”export OS_IDENTITY_API_VERSION3指定用 v3 APIexport OS_PROJECT_NAMEadmin和export OS_USER_DOMAIN_NAMEDefault定义了你要以哪个项目、哪个域的身份登录export OS_USERNAMEadmin和export OS_PASSWORDADMIN_PASS则是你的账号密码。最关键的export OS_PROJECT_DOMAIN_NAMEDefault和export OS_USER_DOMAIN_NAMEDefault这两个变量在 Keystone v3 的多域domain模型中至关重要。OpenStack v3 引入了 domain 概念把用户、项目、角色都划分到不同的域下实现租户隔离。Default是系统内置的根域所有初始资源都在这里。如果漏掉这两个变量openstack user list会报错The request you have made requires authentication.因为 Keystone 不知道你要在哪个域里找用户。把这些 export 命令写进~/.bashrc并source ~/.bashrc是为了让每次打开终端都自动加载避免重复输入。但要注意~/.bashrc只对交互式 shell 生效如果你用 crontab 或 systemd service 运行脚本必须在脚本开头显式 source 它否则环境变量不生效。3.10 Token 获取与验证curl 是终极检验不是花架子一切配置完成后最激动人心的时刻是亲手用最原始的 HTTP 工具验证。curl -i -X POST http://controller:5000/v3/auth/tokens -H Content-Type: application/json -d {auth: {identity: {methods: [password], password: {user: {name: admin, domain: {name: Default}, password: ADMIN_PASS}}}, scope: {project: {name: admin, domain: {name: Default}}}}}这条命令模拟了客户端向 Keystone 发起认证请求的全过程。-i参数显示响应头你最关心的是X-Subject-Token这个 header它的值就是本次认证生成的 token。把这个 token 复制下来再执行curl -H X-Auth-Token: $TOKEN http://controller:5000/v3/projects如果返回一个包含admin项目的 JSON 数组恭喜你Keystone 已经活了。这个过程的价值在于它剥离了所有封装。openstack project list命令背后就是做了这两步先发 auth 请求拿 token再带着 token 去查项目。当你遇到openstack命令报错时第一反应不应该是重装客户端而是用 curl 重走一遍看是第一步认证失败还是第二步token 无效出了问题。这是所有资深 OpenStack 工程师的排错本能。3.11 日志分析/var/log/keystone/keystone.log 是你的“黑匣子”Keystone 启动失败90% 的原因都能在/var/log/keystone/keystone.log里找到答案。但日志不是从头读到尾而是要有目标地扫描。第一搜索ERROR和CRITICAL这是最高优先级的错误。第二搜索Traceback它后面跟着的就是 Python 异常的完整堆栈能精准定位到哪一行代码出错。第三搜索Connection refused这通常指向数据库或 memcache 连接失败。第四搜索No module named说明 Python 包缺失比如No module named pymysql就要sudo apt install python3-pymysql。第五搜索Permission denied这基本可以断定是 Fernet 密钥目录或配置文件的权限问题。一个实用技巧用tail -f /var/log/keystone/keystone.log实时跟踪日志然后在另一个终端执行sudo systemctl restart apache2观察日志里是否有Starting Keystone、Loaded app keystone这样的成功提示。如果只有Stopping...没有Starting...说明 Apache 进程根本没起来这时就要去看/var/log/apache2/error.log那里会记录 WSGI 加载失败的具体原因。3.12 权限与所有权检查Linux 文件权限是 Keystone 的“免疫系统”Keystone 对文件权限极其敏感一个错误的 chmod 就能让整个服务瘫痪。核心权限规则有三条第一/etc/keystone/keystone.conf文件必须属于root:keystone且权限为640-rw-r-----这样 root 可读写keystone 组可读其他用户不可访问防止配置里的数据库密码泄露。第二/etc/keystone/fernet-keys/目录必须属于keystone:keystone且权限为700drwx------确保只有 keystone 用户能进入和读写密钥。第三/var/log/keystone/目录必须属于keystone:keystone权限755这样 Keystone 进程才能写日志而其他用户也能读用于排查。检查方法很简单ls -l /etc/keystone/和ls -ld /etc/keystone/fernet-keys/。如果发现权限不对立刻修复sudo chown root:keystone /etc/keystone/keystone.conf sudo chmod 640 /etc/keystone/keystone.confsudo chown -R keystone:keystone /etc/keystone/fernet-keys/ sudo chmod 700 /etc/keystone/fernet-keys/。这些命令看起来枯燥但它们是 Keystone 稳定运行的基石。我曾见过一个案例运维人员为了“方便”把整个/etc/keystone/目录chmod 777结果 Keystone 启动后疯狂报错Permission denied on fernet key file因为 WSGI 进程以 www-data 用户运行发现密钥文件对所有人都可写出于安全策略自动拒绝加载。4. 实操过程与核心环节实现一份可逐行复制的完整操作清单4.1 环境准备与基础服务安装耗时约 3 分钟我们假设你已有一台纯净的 Ubuntu 22.04 Server 虚拟机网络可达root 权限可用。所有命令均以sudo执行或切换到 root 用户。第一步更新系统并安装基础工具sudo apt update sudo apt upgrade -y sudo apt install -y vim curl wget gnupg software-properties-common第二步配置 NTP 时间同步sudo apt install -y chrony sudo sed -i /^pool/d /etc/chrony/chrony.conf echo server ntp.aliyun.com iburst | sudo tee -a /etc/chrony/chrony.conf sudo systemctl restart chrony sudo chronyc tracking # 验证时间同步状态输出应包含 System clock synchronized: yes第三步配置防火墙sudo ufw allow OpenSSH sudo ufw allow 5000 sudo ufw --force enable第四步配置主机名与 hosts 解析echo 192.168.100.10 controller.example.com controller | sudo tee -a /etc/hosts sudo hostnamectl set-hostname controller.example.com提示请务必将192.168.100.10替换为你实际的服务器 IP 地址。controller.example.com是 FQDN.example.com后缀不能省略这是为了满足 SSL 证书的通用名CN要求即使你现在不用 HTTPS。4.2 MySQL 数据库安装与 Keystone 专用库创建耗时约 2 分钟安装 MySQL 8.0sudo apt install -y mysql-server安全加固设置 root 密码、移除匿名用户等sudo mysql_secure_installation # 按提示操作设置 root 密码记为 MYSQL_ROOT_PASS其余选项选 Y登录 MySQL 并创建 Keystone 数据库与用户sudo mysql -u root -p # 输入上面设置的 MYSQL_ROOT_PASS在 MySQL 提示符下执行CREATE DATABASE keystone CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; CREATE USER keystonelocalhost IDENTIFIED WITH mysql_native_password BY KEYSTONE_DBPASS; CREATE USER keystone% IDENTIFIED WITH mysql_native_password BY KEYSTONE_DBPASS; GRANT ALL PRIVILEGES ON keystone.* TO keystonelocalhost; GRANT ALL PRIVILEGES ON keystone.* TO keystone%; FLUSH PRIVILEGES; EXIT;注意KEYSTONE_DBPASS是你为 Keystone 数据库用户设定的密码请牢记。keystone%的授权是为了未来扩展现在可以先用keystonelocalhost。4.3 Keystone 服务安装与系统用户创建耗时约 1 分钟安装 Keystone 及其依赖sudo apt install -y keystone apache2 libapache2-mod-wsgi-py3 python3-openstackclient创建 Keystone 系统用户与组sudo useradd -r -s /bin/false keystone sudo groupadd keystone sudo usermod -a -G keystone keystone创建日志与密钥目录sudo mkdir -p /var/log/keystone /etc/keystone/fernet-keys sudo chown -R keystone:keystone /var/log/keystone /etc/keystone/fernet-keys sudo chmod 755 /var/log/keystone sudo chmod 700 /etc/keystone/fernet-keys4.4 Keystone 主配置文件编辑耗时约 5 分钟需逐行核对备份原始配置sudo cp /etc/keystone/keystone.conf /etc/keystone/keystone.conf.bak清空并重写配置文件使用 vim 或 nanosudo tee /etc/keystone/keystone.conf EOF [DEFAULT] log_dir /var/log/keystone transport_url rabbit://openstack:RABBIT_PASScontroller [database] connection mysqlpymysql://keystone:KEYSTONE_DBPASScontroller/keystone [token] provider fernet driver sql [cache] backend dogpile.cache.memcached memcache_servers localhost:11211 [identity] driver sql [assignment] driver sql [auth] methods external,password,token,oauth1 password password token token [profiler] enabled false EOF设置正确权限sudo chown root:keystone /etc/keystone/keystone.conf sudo chmod 640 /etc/keystone/keystone.conf提示RABBIT_PASS是 RabbitMQ 的密码占位符本实训暂不启用消息队列但此行必须存在否则 Keystone 启动失败。KEYSTONE_DBPASS请替换为你在 4.2 步骤中设定的密码。4.5 Fernet 密钥初始化与数据库同步耗时约 1 分钟初始化 Fernet 密钥sudo keystone-manage fernet_setup --keystone-user keystone --keystone-group keystone sudo keystone-manage credential_setup --keystone-user keystone --keystone-group keystone同步数据库表结构sudo keystone-manage db_sync注意db_sync命令无任何输出即为成功。如果报错请立即检查 MySQL 连接字符串和权限。4.6 Bootstrap 初始化与 Apache 配置耗时约 2 分钟执行初始化创建 admin 用户与 servicesudo keystone-manage bootstrap --bootstrap-password ADMIN_PASS \ --bootstrap-admin-url http://controller:5000/v3/ \ --bootstrap-internal-url http://controller:5000/v3/ \ --bootstrap-public-url http://controller:5000/v3/ \ --bootstrap-region-id RegionOneADMIN_PASS是你为 admin 用户设定的密码请牢记。controller必须与/etc/hosts中配置的主机名完全一致。配置 Apachesudo tee /etc/apache2/sites-available/wsgi-keystone.conf EOF Listen 5000 VirtualHost *:5000 WSGIDaemonProcess keystone-public processes5 threads1 userkeystone groupkeystone display-name%{GROUP} WSGIProcessGroup keystone-public