OpenStack Keystone手动安装与身份治理原理详解 📅 2026/7/17 23:03:59 1. 这不是“装个软件”Keystone手动安装背后的OpenStack身份治理逻辑很多人看到“Keystone手动安装与配置”这个标题第一反应是“哦又一个Linux服务安装教程改改配置文件、跑几条命令、重启下服务就完事了。”我当年第一次在实训课上也是这么想的——直到我把keystone-manage db_sync执行了三遍数据库里还是空空如也而openstack user list报出一长串Connection refused。那一刻我才真正意识到Keystone不是Apache或Nginx那种“开箱即用”的Web服务它是一套运行在OpenStack心脏位置的身份治理引擎它的安装过程本质上是在为整个云平台铺设信任地基。为什么必须手动安装因为自动化脚本比如DevStack会把所有依赖、证书、数据库初始化全包圆你点个回车就完事。但实训项目要训练的恰恰是你对这套机制的“解剖能力”当你亲手敲下openssl rand -hex 10生成admin_token你是在理解服务间通信的密钥协商机制当你手动编辑/etc/keystone/keystone.conf里的connection字段你是在建立对OpenStack服务网格拓扑的具象认知当你执行keystone-manage pki_setup你不是在运行一个黑盒命令而是在亲手部署一套微型PKI公钥基础设施为后续所有API调用签发和验证JWT令牌。这就像学开车自动挡能让你上路但只有摸过离合、踩过油门、感受过发动机转速与车速的咬合关系你才算真正懂了“驱动”。关键词里反复出现的“Keystone”绝非一个孤立名词。它和“MySQL安装配置教程”“git安装及配置教程”这些并列热词的本质区别在于后两者是工具链的起点而Keystone是整个OpenStack服务生态的守门人。没有它Nova无法验证虚拟机创建请求是否来自合法租户Glance无法确认镜像上传者是否有权限Horizon控制台连登录框都弹不出来。所以本次实训的底层目标从来不是“让Keystone进程跑起来”而是让你建立起一个清晰的判断链当OpenStack某个服务报401 Unauthorized时问题90%不在那个服务本身而在Keystone的token签发、验证或数据库状态上。这种系统级排错思维才是企业云平台运维工程师的核心竞争力。我带过的几十届学生里80%的人卡在第一步——环境准备。他们习惯性地跳过getent hosts controller这行命令直接在配置文件里写死127.0.0.1结果Keystone服务启动后其他OpenStack服务比如Nova根本连不上它因为它们被配置成通过主机名controller访问。这不是笔误这是对OpenStack分布式架构最基础的信任模型缺乏认知。Keystone要求所有服务节点通过可解析的、一致的主机名进行通信这是为了支持未来横向扩展——当你的云平台从单节点发展到多节点时controller这个逻辑名称将指向一个VIP或负载均衡器而不是某台物理机的IP。所以实训的第一课其实是教你如何像一个云架构师那样思考每一个配置项都是在为未来的弹性伸缩埋下伏笔。提示不要急于复制粘贴命令。在敲下pkg install keystoneSolaris或apt install keystoneUbuntu之前请先确认你的操作系统版本与OpenStack发行版的兼容性。Havana、Juno、Queens各版本对Python版本、数据库驱动、SSL库的要求差异极大。我见过太多人因为用Ubuntu 22.04硬装OpenStack Queens结果pip依赖冲突到凌晨三点——这不是技术问题是项目规划问题。2. 环境筑基从主机名解析到数据库授权的七道关卡手动安装Keystone前30分钟的工作量可能占整个项目50%的精力。这不是夸张而是因为OpenStack对环境的“洁癖”程度远超常规应用。它要求一个高度可控、命名规范、权限分明的基础环境。任何一处疏忽都会在后续keystone-manage db_sync或openstack user create阶段以晦涩的错误码爆发出来。下面这七道关卡是我用三年生产环境排障经验总结出的“必过清单”漏掉任意一道后面全是坑。2.1 主机名解析不只是/etc/hosts那么简单OpenStack所有服务间的通信强制使用主机名hostname而非IP地址。这看似简单但实操中陷阱重重。很多同学会直接在/etc/hosts里加一行127.0.0.1 controller这在单机测试时看似可行但一旦你尝试从另一台机器比如计算节点访问Keystone就会失败。原因在于127.0.0.1是本地回环地址只对本机有效。正确的做法是让controller这个主机名解析到你的实际管理网络IP比如192.168.1.10。更关键的是你需要验证解析的双向一致性。执行以下两条命令输出必须完全相同# 查看本机hostname hostname # 查看hostname对应的IP getent hosts $(hostname) | awk {print $1}如果hostname输出是controller而getent hosts controller返回的是127.0.0.1那你就掉坑里了。修复方法是修改/etc/hosts确保controller映射到真实IP并且/etc/hostname文件里写的也是controller。在Solaris系统中还需检查/etc/nodename文件。这一步的哲学意义在于OpenStack不信任“我”它只信任“controller”这个身份标识。你的机器必须向整个网络宣告自己就是controller且这个宣告必须被所有节点准确接收。2.2 MySQL数据库创建专用用户与库的精确指令Keystone需要一个独立的MySQL数据库来存储用户、租户、角色、服务端点等核心元数据。很多人图省事直接用root用户连接这是严重违反安全原则的。Keystone官方文档明确要求创建专用用户其权限必须严格限定。在MySQL中执行以下命令注意替换YOUR_PASSWORD-- 创建keystone数据库字符集必须为utf8mb4否则中文用户名会乱码 CREATE DATABASE keystone CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; -- 创建keystone用户密码强度必须符合MySQL 5.7的默认策略至少8位含大小写字母、数字、特殊符号 CREATE USER keystonelocalhost IDENTIFIED BY YOUR_PASSWORD; CREATE USER keystone% IDENTIFIED BY YOUR_PASSWORD; -- 授予keystone用户对keystone数据库的全部权限仅此库 GRANT ALL PRIVILEGES ON keystone.* TO keystonelocalhost; GRANT ALL PRIVILEGES ON keystone.* TO keystone%; -- 刷新权限使配置立即生效 FLUSH PRIVILEGES;这里有两个极易被忽略的细节第一keystone%这个用户是必须的。因为Keystone服务本身可能运行在controller节点但其他OpenStack服务如Nova可能运行在不同节点它们需要通过网络连接MySQLlocalhost用户只允许本机socket连接。第二utf8mb4字符集是硬性要求。OpenStack Queens及以后版本大量使用Unicode emoji和生僻字作为资源描述utf8实际是utf8mb3无法支持四字节UTF-8字符会导致keystone-manage db_sync中途报错Incorrect string value。2.3 Python环境与依赖避开pip地狱的务实方案Keystone是一个Python应用但它对Python版本和第三方库的版本有极其苛刻的要求。例如OpenStack Victoria要求Python 3.6而Queens则要求Python 2.7或3.5。盲目升级pip或用pip install --upgrade全局更新极可能导致系统Python环境崩溃尤其在Ubuntu/Debian上apt和pip混用是大忌。我的建议是永远优先使用系统包管理器安装Keystone主程序仅用pip管理其特定依赖。在Ubuntu 20.04上# 使用apt安装keystone及其核心依赖它会自动处理Python版本兼容性 sudo apt update sudo apt install keystone apache2-utils # 检查keystone安装的Python路径通常是/usr/bin/keystone-manage which keystone-manage # 如果需要额外安装某个库比如pymysql指定Python解释器 sudo /usr/bin/python3 -m pip install pymysql这样做的好处是apt安装的包经过了发行版维护者的严格测试版本锁死不会与系统其他组件冲突。而pip只用于补充那些apt仓库里没有的、Keystone运行时必需的库。我曾帮一个团队解决过一个持续两周的bug他们的keystone-manage db_sync总在sqlalchemy库上失败最后发现是有人用pip3 install --upgrade sqlalchemy把版本升到了2.0而Keystone Wallaby只兼容1.4.x。降级回1.4.48后问题瞬间消失。教训就是在OpenStack世界里新版本不等于好版本稳定压倒一切。2.4 网络与防火墙为API端口打开一扇合规的门Keystone默认监听两个端口5000public API和35357admin API。在旧版OpenStack如Juno中这两个端口是分开的新版Queens已合并为5000但35357仍需保留兼容性。很多同学装完后curlhttp://controller:5000返回Connection refused第一反应是服务没起来其实90%的情况是防火墙拦住了。在Ubuntu上使用ufw# 允许5000和35357端口的TCP入站连接 sudo ufw allow 5000/tcp sudo ufw allow 35357/tcp # 重新加载防火墙规则 sudo ufw reload在CentOS/RHEL上使用firewalldsudo firewall-cmd --permanent --add-port5000/tcp sudo firewall-cmd --permanent --add-port35357/tcp sudo firewall-cmd --reload但比开放端口更重要的是理解端口背后的服务分层逻辑。5000端口面向所有租户用户提供标准的OpenStack Identity API35357端口则只应暴露给管理员和内部服务它提供了更高级的管理接口如keystone-manage的某些功能。因此在生产环境中35357端口绝不应该对公网开放甚至不应该对普通计算节点开放只应允许controller节点自身和network节点访问。这体现了OpenStack最小权限原则每个服务只拥有完成其任务所必需的最低限度网络权限。2.5 时间同步NTP服务是信任链的隐形基石这是一个绝大多数新手会忽略但却是导致Keystone最诡异故障的根源——时间不同步。Keystone颁发的JWTJSON Web Token包含exp过期时间和nbf生效时间声明这些时间戳是基于UTC的。如果controller节点和compute节点的系统时间相差超过5分钟这是OpenStack的默认容忍阈值compute节点收到的token就会被判定为“尚未生效”或“已过期”从而拒绝所有API请求错误日志里只会显示模糊的Invalid token。解决方案是强制所有OpenStack节点使用同一个NTP服务器# Ubuntu/Debian sudo timedatectl set-ntp on sudo systemctl restart systemd-timesyncd # 或者手动配置NTP客户端推荐使用国内NTP池 echo server ntp.aliyun.com iburst | sudo tee -a /etc/systemd/timesyncd.conf sudo systemctl restart systemd-timesyncd验证同步状态timedatectl status | grep System clock synchronized # 输出应为 yes ntpq -p # 应能看到一个*号标记的活动NTP源这个步骤的重要性怎么强调都不为过。它不像数据库或网络配置那样有直观的错误提示但它会让整个云平台处于一种“亚健康”状态服务看似都在运行但资源创建成功率忽高忽低日志里充斥着无法复现的认证失败。我把它称为“幽灵故障”而NTP就是驱散这个幽灵的唯一咒语。2.6 SELinux/AppArmor安全模块的温柔一刀在CentOS/RHELSELinux或UbuntuAppArmor上安全模块默认会阻止Keystone进程访问其所需的文件和端口。如果你在systemctl status keystone里看到Permission denied或者journalctl -u keystone里有avc: denied字样那基本可以确定是SELinux在作祟。临时禁用仅用于调试# CentOS/RHEL sudo setenforce 0 # Ubuntu (AppArmor) sudo systemctl stop apparmor但这只是治标。永久解决方案是为Keystone创建自定义策略# CentOS/RHEL: 生成并安装策略模块 sudo ausearch -m avc -ts recent | audit2allow -M keystone sudo semodule -i keystone.pp对于实训项目我建议采用折中方案在/etc/selinux/config中将SELINUXenforcing改为SELINUXpermissive。permissive模式下SELinux依然会记录所有违规操作写入/var/log/audit/audit.log但不会阻止进程执行。这既能保证服务正常运行又能为你提供一份详尽的“安全审计报告”告诉你Keystone到底需要哪些权限。这份报告就是你理解OpenStack安全模型的最佳教材。2.7 管理员凭据admin_token不是密码而是启动密钥admin_token是Keystone安装过程中最常被误解的概念。很多人把它当成一个“管理员密码”随意设置一个字符串甚至写在配置文件里明文保存。这是巨大的安全隐患。admin_token的真实身份是Keystone服务启动时用于初始化自身数据库和内部服务注册的“一次性启动密钥”。它的生命周期极短仅在keystone-manage db_sync和keystone-manage bootstrap新版执行期间有效。一旦初始化完成Keystone就会切换到基于数据库的token持久化机制admin_token便彻底失效。因此它的安全性要求是足够随机但无需长期保密。生成方式必须使用密码学安全的随机数生成器# 正确使用openssl生成10字节20字符十六进制随机串 ADMIN_TOKEN$(openssl rand -hex 10) echo $ADMIN_TOKEN # 输出类似a1b2c3d4e5f678901234 # 错误使用date或$RANDOM它们不具备密码学安全性 WRONG_TOKEN$(date %s%N | sha256sum | cut -c1-20)将$ADMIN_TOKEN填入/etc/keystone/keystone.conf的[DEFAULT]区段[DEFAULT] admin_token a1b2c3d4e5f678901234记住这只是启动钥匙。初始化完成后你必须立即删除这一行或将其注释掉并改用openstack命令行工具通过admin用户和密码进行认证。这就像汽车的点火钥匙——启动后你就该把它拔下来收好而不是一直插在点火开关上。3. 配置深潜keystone.conf文件中每一行代码的生存意义/etc/keystone/keystone.conf不是一份静态的说明书而是一份动态的“服务契约”。它定义了Keystone如何与外部世界数据库、消息队列、缓存、其他OpenStack服务交互以及它内部各个组件如何协同工作。逐行解读这份文件是理解OpenStack身份认证体系的捷径。下面我将带你穿透表层语法直击每一类配置项背后的设计哲学与实战考量。3.1[database]区段连接字符串里的信任与隔离这是Keystone配置中最核心的一环决定了它能否“活下来”。连接字符串connection mysqlpymysql://keystone:YOUR_PASSWORDcontroller/keystone表面看只是数据库地址实则蕴含三层关键信息第一层协议与驱动选择mysqlpymysql明确指定了使用PyMySQL这个纯Python实现的MySQL驱动而非mysqlclientC扩展。在容器化或受限环境如某些Alpine Linux镜像中mysqlclient因依赖C编译器而难以安装PyMySQL就成了唯一可靠的选择。如果你遇到ImportError: No module named MySQLdb十有八九是驱动不匹配。第二层用户与权限的精准映射keystone:YOUR_PASSWORD这部分必须与你在MySQL中创建的keystone用户完全一致。这里有个反直觉的细节keystone用户在MySQL中的主机名是%但在连接字符串里controller中的controller必须能被Keystone进程正确解析为一个IP地址。如果controller解析失败连接会超时错误日志里只会显示OperationalError: (pymysql.err.OperationalError) (2003, Cant connect to MySQL server on controller)非常误导人。因此getent hosts controller的验证必须在此步之前完成。第三层数据库名的语义约束/keystone末尾的数据库名必须与MySQL中CREATE DATABASE keystone的名称严格一致且区分大小写在Linux文件系统上。我曾见过一个案例管理员在MySQL里创建的是KEYSTONE全大写而配置文件里写的是keystone小写结果keystone-manage db_sync静默失败没有任何错误提示数据库里空空如也。这是因为MySQL在Linux上对数据库名是大小写敏感的。这个细节完美诠释了OpenStack配置的“零容错”特性——它不帮你做任何智能转换你给什么它就信什么。3.2[token]区段JWT令牌的生命周期与存储策略OpenStack Queens之后Keystone默认使用fernet令牌格式取代了旧版的uuid和pki。fernet是一种对称加密的轻量级令牌性能远超pki且无需复杂的证书管理。配置如下[token] provider fernet driver sql expiration 3600provider fernet告诉Keystone生成和验证token时使用Fernet对称加密算法。这意味着所有运行Keystone服务的节点必须共享同一套Fernet密钥。密钥存放在/etc/keystone/fernet-keys/目录下由keystone-manage fernet_setup命令生成。driver sql指示Keystone将token的元数据如创建时间、所属用户存储在SQL数据库中而不是内存或memcached。这是为了保证高可用性——即使某个Keystone实例宕机其他实例也能从数据库中查询到有效的token状态。expiration 3600设置token有效期为3600秒1小时。这个值不能设得过大否则一旦管理员密码泄露攻击者持有的token会长期有效也不能过小否则客户端如Horizon会频繁要求用户重新登录体验极差。3600是社区公认的平衡点。一个关键的实操心得fernet密钥轮换是必须掌握的技能。密钥文件夹/etc/keystone/fernet-keys/里会有多个编号的密钥文件如0、1、2。0号是当前主密钥用于签发新token1号是次密钥用于验证旧token。当执行keystone-manage fernet_rotate时1号会变成新的0号旧的0号会变成2号。这个机制保证了在密钥轮换期间新旧token都能被正确验证实现了无缝切换。在实训中你可以手动执行一次轮换然后观察openstack token issue生成的token是否依然能被openstack user list成功验证。3.3[cache]区段Redis不是可选项而是性能加速器虽然Keystone可以不配置缓存而运行但一旦你的云平台用户量超过100没有缓存的Keystone会成为整个系统的性能瓶颈。[cache]区段的配置直接决定了API响应速度[cache] backend dogpile.cache.redis backend_argument url:redis://127.0.0.1:6379/0 expiration_time 300backend dogpile.cache.redis指定了使用Redis作为缓存后端。dogpile.cache是Python的一个通用缓存库redis是其具体实现。这里不能写成redis必须是完整的dogpile.cache.redis。backend_argument url:redis://127.0.0.1:6379/0Redis连接URL。/0表示使用Redis的第0号数据库。OpenStack官方建议为每个服务分配独立的Redis DB避免key冲突。例如Nova用DB 1Glance用DB 2。expiration_time 300缓存项的过期时间单位为秒。这个值需要根据你的业务场景调整。对于用户信息user info300秒5分钟很合理因为用户资料很少实时变更但对于服务目录service catalog可以设为600秒10分钟因为服务端点的变更频率更低。一个血泪教训在实训环境里很多人会忽略Redis服务本身的安装和启动。keystone.conf里配好了但systemctl status redis-server显示inactive。结果就是Keystone启动时会疯狂重试连接Redis日志刷屏而openstack命令行却表现得“一切正常”只是响应慢得像蜗牛。所以在配置[cache]之前请务必先执行sudo apt install redis-server sudo systemctl enable redis-server sudo systemctl start redis-server3.4[identity]与[assignment]区段用户与角色的权限骨架这两个区段共同构建了OpenStack的RBAC基于角色的访问控制模型。[identity]管理“你是谁”[assignment]管理“你能做什么”。[identity] driver sql # 这行告诉Keystone用户、租户project、域domain等身份信息都存在SQL数据库里 [assignment] driver sql # 这行告诉Keystone角色role、角色分配role assignment、组group等权限信息也存在SQL数据库里看起来很简单但这里隐藏着一个重大设计决策Keystone默认不支持LDAP或AD集成。driver sql意味着所有用户和角色都必须通过openstack命令行或API手动创建。这对于实训项目是完美的因为它强迫你亲手搭建起整个权限体系。你可以执行# 创建一个名为demo的域 openstack domain create --description Demo Domain demo # 在demo域下创建一个名为demo的项目租户 openstack project create --domain demo --description Demo Project demo # 创建一个名为demo的用户并为其设置密码 openstack user create --domain demo --password-prompt demo # 创建一个名为user的角色 openstack role create user # 将user角色分配给demo用户在demo项目上 openstack role add --project demo --user demo user这个过程就是你在[identity]和[assignment]配置下亲手绘制出的权限地图。每一条openstack命令都在数据库里插入了一行记录。理解这一点你就明白了为什么keystone-manage db_sync是初始化的第一步——它创建了这些数据表的结构而openstack命令则是往这些表里填充血肉。3.5[eventlet_server]区段并发模型的无声革命OpenStack从Newton版本开始全面拥抱eventlet协程库取代了传统的多线程/多进程模型。[eventlet_server]区段正是为此而生[eventlet_server] workers 4 # 设置Keystone服务的worker进程数。通常设为CPU核心数的1-2倍 max_header_line 16384 # 增大HTTP请求头的最大长度以支持携带大量token信息的复杂请求workers 4这个配置直接影响Keystone的吞吐量。在单核VM上设为1即可在4核的controller节点上设为4是合理的。但切记workers不是越多越好。每个worker进程都会消耗内存和数据库连接。如果MySQL的max_connections参数设得太低默认151当workers设为8时Keystone可能因为拿不到数据库连接而卡死。因此workers的值必须与MySQL的max_connections相匹配公式是max_connections workers * 2 10预留10个连接给其他管理操作。max_header_line 16384则是一个典型的“踩坑后才懂”的配置。当Keystone与某些前端代理如HAProxy或复杂的OAuth2网关集成时HTTP请求头会变得异常庞大里面可能嵌套了多层认证信息。默认的8192字节上限会被轻易突破导致Keystone直接返回400 Bad Request错误日志里只有一行Request header or cookie too large。把这个值翻倍是应对现代云原生架构的必备操作。4. 初始化与验证从db_sync到openstack user list的完整闭环当keystone.conf配置完毕环境准备就绪真正的考验才刚刚开始。初始化Initialization不是一键式的魔法而是一个需要你全程监控、理解每一步意图的精密手术。下面我将带你走完从空数据库到可验证API的完整闭环每一步都附带“为什么这么做”和“如果失败了怎么办”的深度解析。4.1 数据库同步keystone-manage db_sync的成败之钥这是Keystone启动前最关键的一步它负责在MySQL中创建所有必需的数据表。命令本身只有一行sudo keystone-manage db_sync但它的背后是SQLAlchemy ORM对象关系映射将Python模型类如User,Project,Role翻译成SQL DDL数据定义语言语句并在数据库中执行。这个过程的成败直接取决于前面所有环境配置的正确性。成功标志命令执行后终端无任何输出静默成功且MySQL中keystone数据库里出现了数十张表如user,project,role,assignment,endpoint等。你可以用以下命令快速验证mysql -u keystone -p -D keystone -e SHOW TABLES; | wc -l # 输出应大于30常见失败与排错错误ModuleNotFoundError: No module named pymysql原因Python环境缺少MySQL驱动。解决方案sudo pip3 install pymysql确保pip3对应的是Keystone使用的Python版本。错误pymysql.err.OperationalError: (1045, Access denied for user ...)原因keystone.conf中的数据库用户名或密码错误或MySQL用户权限未正确授予。解决方案回到2.2节重新检查GRANT语句和FLUSH PRIVILEGES。错误sqlalchemy.exc.ProgrammingError: (pymysql.err.ProgrammingError) (1146, Table keystone.migrate_version doesnt exist)原因keystone数据库为空但db_sync命令期望一个已存在的migrate_version表来跟踪迁移历史。这通常是因为你之前执行过db_sync但失败了残留了一个不完整的数据库。解决方案清空并重建数据库DROP DATABASE keystone; CREATE DATABASE keystone CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;然后重试db_sync。注意db_sync命令本身不创建数据库它只在已存在的数据库中创建表。创建数据库是DBA数据库管理员的职责db_sync只是“装修工”。4.2 Fernet密钥初始化keystone-manage fernet_setup的不可逆操作在db_sync成功后下一步是为fernet令牌机制准备加密密钥。这一步是fernet模式启用的前提sudo keystone-manage fernet_setup --keystone-user keystone --keystone-group keystone这条命令会在/etc/keystone/fernet-keys/目录下生成一个初始密钥文件通常是0号文件。--keystone-user和--keystone-group参数确保了生成的密钥文件权限正确属主为keystone用户防止其他用户读取。为什么必须做因为fernet令牌的签发和验证依赖于一个共享的、对称的密钥。没有这个密钥Keystone无法生成任何有效的token所有API请求都会失败。fernet_setup就是这个密钥的“诞生仪式”。一个关键细节fernet_setup命令不会覆盖已存在的密钥。如果你已经有一个0号密钥再次运行它什么也不会发生。这保证了密钥的安全性——你不会因为手抖而意外丢失主密钥。如果你想强制重新生成必须先手动删除/etc/keystone/fernet-keys/目录下的所有文件。4.3 Bootstrap初始化keystone-manage bootstrap的终极授权这是整个初始化流程的高潮也是最具“仪式感”的一步。bootstrap命令会执行一系列原子操作创建管理员用户、服务项目、admin角色并将admin角色赋予admin用户同时注册Keystone自身的服务和端点。它相当于为整个OpenStack云平台举行了“加冕礼”。sudo 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 RegionOne--bootstrap-password ADMIN_PASS这是admin用户的密码请务必牢记。这是你登录Horizon或使用openstack命令行的唯一凭证。--bootstrap-*-url这三个URL分别对应Keystone服务的Admin、Internal和Public API端点。在单节点实训中它们都指向http://controller:5000/v3/。v3是OpenStack Identity API的最新稳定版本必须显式指定。--bootstrap-region-id RegionOneRegionOne是OpenStack的默认区域ID。所有服务端点都必须注册到一个区域下这是多区域部署的基础。成功标志命令执行后终端输出Bootstrap complete.且openstack命令行可以开始工作。此时你可以用admin用户获取一个tokenopenstack --os-auth-url http://controller:5000/v3 \ --os-project-domain-name Default \ --os-user-domain-name Default \ --os-project-name admin \ --os-username admin \ --os-password ADMIN_PASS \ --os-identity-api-version 3 \ token issue如果返回一个长长的JWT字符串恭喜你Keystone的核心功能已经打通4.4 环境变量脚本admin-openrc的便捷与风险每次执行openstack命令都输入一长串参数显然不现实。admin-openrc脚本就是为了解决这个问题而生的。创建它cat admin-openrc EOF export OS_PROJECT_DOMAIN_NAMEDefault export OS_USER_DOMAIN_NAMEDefault export OS_PROJECT_NAMEadmin export OS_USERNAMEadmin export OS_PASSWORDADMIN_PASS export OS_AUTH_URLhttp://controller:5000/v3 export OS_IDENTITY_API_VERSION3 export OS_IMAGE_API_VERSION2 EOF然后加载它source admin-openrc现在openstack token issue就能直接工作了。但这里有一个巨大的安全风险admin-openrc文件里明文存储了admin密码。如果这个文件被未授权用户读取整个云平台就沦陷了。因此在生产环境中绝对禁止将密码写入admin-openrc。正确的做法是使用OS_PASSWORD环境变量但密码由用户在shell中手动输入或者使用更安全的凭据管理工具如HashiCorp Vault。在实训环境中为了教学便利我们接受这个风险但你必须清楚地知道便利性与安全性永远是一对矛盾体而生产环境必须向安全性妥协。4.5 全链路验证用openstack命令行构建你的第一个租户初始化的最终验证不是看某个命令是否成功而是看能否用Keystone提供的API构建出一个最小但完整的云租户环境。这包括四个核心实体Domain域、Project项目/租户、User用户、Role角色。执行以下命令# 1. 创建一个名为demo的域 openstack domain create demo # 2. 在demo域下创建一个名为demo的项目 openstack project create --domain demo demo # 3. 创建一个名为demo的用户并设置密码系统会提示你输入 openstack user create --domain demo --password-prompt demo