本帖最后由 tallfish 于 2015-10-12 10:29 编辑
产生背景 早期OpenStack版本中,用户、消息、API调用的认证都是放在Nova中。后来由于各种模块加入OpenStack中,安全认证涉及更加广泛,如用户登录、用户消息传递、模块消息通信,服务注册各不相同的认证。就产生了Keystone模块来处理不同的安全认证。
提供的服务 1.身份验证:负责验证从各个组件或者客户端发来的请求,有两种验证方式 2.授权:向通过验证的客户端授予token令牌,设置哪些服务可以访问 3.目录服务:将客户端提供可访问服务的URL PS:OpenStack上所有服务都在Keystone上注册,所以OpenStack的安装要从Keystone入手
Keystone概念 证书(Credentials):数据只被数据的所有者知道,数据所有者可以证明数据是自己的。 认证(Authentication):身份认证服务会确认谁正在发送服务请求。初次的身份请求将通过一系列凭证来确认用户身份,通过后,用户可以获得身份认证服务的访问令牌。 令牌(Token):访问令牌具有时间限制,持续时间,并且可以在任意时间里撤销令牌 服务(Service):一个服务提供一个或者多个访问端点,用户通过访问端点访问资源或执行可能有用的操作 访问端点(Endpoint):一个可通过网络访问的地址,通常由可访问服务的URL来描述 用户(User):个人、系统或服务的一个数字化表现形式,决定谁可以使用OpenStack。当用户发来访问请求时,Keystone将验证输入请求,用户通过Keystone发放的令牌OpenStack服务资源 租户(Tenant):用于分组或者分离的资源和/或便是对象的容器。根据不同的服务运营商,租客可以映射到一个客户、账户、组织或者项目 角色(Role):个性化的用户可执行一组特定的操作,角色包括一组权利和特权。如果用户担当某一个角色,就可以继承角色的权利和特权。 PS:当发送请求到OpenStack的服务时,必须指定一个租户。用户可以在不同的租户承担不同的角色,一个用户也可以在一个租户下承担多种角色。在Keystone服务中,发放的令牌决定了用户的角色。
身份认证 客户端: 在Keystone的Client类初始化时,就会执行用户认证。 1.获取外部传入的用户名、密码、Token和租户等参数 2.获取用户缓存在本地的Token,如果Token不存在或过期就向Keystone服务器发送HTTP请求,获取新的Token 3.根据获取的Token设置用户的权限 4.将用户最新的Token保存在本地keyring中。
服务端: 用户名密码方式认证:在/usr/share/Keystone/Keystone-dist=paste.ini中的public_service和admin_service应用程序。有定义。主要调用token_controller对象的authenticate()方法来进行用户认证。Keystone共实现了3种认证方式 Token认证:通过已经存在的Token来认证用户的身份,一般保存在内存中。在api-paste.ini配置文件中调用authtoken过滤器中auth_token包的filter_factory方法。此方法会返回一个AuthProtocol的实例。当authtoken过滤器接收到HTTP请求时,会调用AuthProtocol实例的_call_方法: 1. 调用_remove_auth_headers方法,防止用户越权。客户端向服务端发送验证请求时,应该只提供TokenID,为了防止HTTP头部提供租户等字段谋取非法的权限,所以需要删除这些多余字段 2. 调用_validate_user_token方法,从现有的HTTP请求头收集Token,实现Token ID真实性的验证。处理UUID格式的Token使用verify_uuid_token方法: 1) 调用get_admin_token方法,获取用户TokenID。如果Token过期,则使用api-paste.ini指定的用户名和密码向Keystone服务器申请新的Token并保存在本地(内存)中 2) 调用_json_request方法向Keystone服务器发送请求,验证用户的Token。 3. 调用_build_user_headers方法,根据获取的Token信息,重新将用户、服务目录等字段加到HTTP头 本地认证:通过用户名和密码来认证用户的身份,通常用于客户端找不到用户的Token或者保存的Token失效的情况。这类用户的信息是保存在Keystone的数据库中。 外地认证:需要httpd服务 admin_token方式认证:定义在/usr/share/Keystone/Keystone-dist=paste.ini中的admin_token_auth过滤器中。对比客户端传来的Token与配置文件中的admin_token是否一致。在使用用户名密码方式验证时,一般会指定用户所属的租户,因此权限收到严格的约束。而通过admin_token方式认证,用户可以获得完全的权限。在OpenStack其他组件中,由于很多资源都必须属于某一个租户,因此只能通过Token方式认证。
认证过程 Keystone的PasteDeploy配置定义在/usr/share/Keystone/Keystone-dist=paste.ini中。OpenStack服务中,通常使用composite部件来定义服务的入口。以下两个服务都定义了3个url映射,即/v2.0、/v3.0和/。一般使用的是/v2.0映射 5000监听端口-公共服务的入口,公共服务用于实现用户名密码方式的认证
sizelimit:判断request的大小 url_nomalize:处理request中的url,如删去url最后的’/’ build_auth_context:生成auth context token_auth:在request.environ字典中,加入token信息 xml_body:将reques格式从xml转化为json json_body:将json格式的request进行解析 user_crud_extension[过滤器]:添加用户密码修改的url映射 public_service[应用程序]:添加用户密码方式认证,查询用户所属租户的url映射
35357监听端口-管理服务的入口,管理服务实现对Keystone各类资源的增、删、改、查
sizelimit:判断request的大小 url_nomalize:处理request中的url,如删去url最后的’/’ build_auth_context:生成auth context token_auth:在request.environ字典中,加入token信息 xml_body:将reques格式从xml转化为json json_body:将json格式的request进行解析 crud_extension[过滤器]:添加对用户、租户、角色、服务和端点等资源管理的url映射 admin_service[应用程序]:添加用户名密码方式认证,用户、租户信息查询的url映射
以上这些类的方法都调用mapper对象的connect方法来添加url映射。调用connect方法时,须指定以下4个参数: 1.HTTP请求的url格式,例 创建租户请求对应的URL为 '/tenant' 2.处理请求的Controller对象,例 处理与租户资源有关的HTTP请求的方法为tenant_controller对象的create_tenant方法controller=tenant_controller 3.处理请求的方法,该方法是指Controller对象中定义的方法action='create_tenant' 4.请求的条件,通常指定HTTP请求的方法,有GET、POST、PUT、DELETE、PATCH等conditions=dict(method=['POST']) POST(创建):创建一个子资源,POST方法不是冥等的,多次执行,将导致多条相同的相同的用户被创建 PUT(更新或者创建):是冥等的,创建一个URL已知的资源,或者对已知资源进行完全替换 PATCH:是对PUT方法的补充,用来对已知资源进行局部更新 DELETE(删除):是冥等的 GET(查看):是冥等的,可以被浏览器缓存,长度有所限制(2048个字符),请求的数据只能包含ASCII字符 PS:冥等:不管进行多少次操作,结果都是一样的
验证Keystone API -i/--include 输出时包括protocol头信息 -H/--header <line>自定义头信息传递给服务器 -X/--request <command>指定什么命令 -d/--data <data> HTTP POST方式传送数据 List: List/Show/Update/Deleteservices: List endpoints: curl-s -H "X-Auth-Token:$OS_TOKEN" http://controller:5000/v3/endpoints |python -mjson.tool curl-s -H "X-Auth-Token:$user_token"http://controller:35357/v2.0/tokens/$user_token/endpoints | python -mjson.tool Listprojects(tenants): curl-s -H "X-Auth-Token:$OS_TOKEN" http://controller:5000/v3/projects |python -mjson.tool curl-s -H "X-Auth-Token:$user_token" http://controller:5000/v2.0/tenants| python -mjson.tool List users: curl-s -H "X-Auth-Token:$OS_TOKEN" http://controller:5000/v3/users | python -mjson.tool List the role a userhas been granted on a tenant: curl-s -H "X-Auth-Token:$user_token"http://controller:35357/v2.0/tenants/$tenant_id/users/$user_id/roles List version: List api-extensions: curl-s http://controller:5000/v2.0/extensions | python -mjson.tool Token Get X-Auth-Token foran access token: curl-s -H "Content-type: application/json" -d'{"auth":{"tenantName": "admin", "passwordCredentials":{"username": "admin", "password":"redhat"}}}' http://controller:35357/v2.0/tokens | python -mjson.tool Get X- Subject -Tokenfor an access token: curl-i -H "Content-Type:application/json" -d '{ "auth":{"identity":{"methods":["token"],"token":{"id":"$user_token "}}}}' http://controller:5000/v3/auth/tokens ; echo Validate a token: curl-s -H "X-Auth-Token:$user_token" -H "X-Subject-Token:$sbj_token"http://controller:35357/v2.0/tokens/$user_token | python -mjson.tool project Disable a project: curl-s -X PATCH -H "X-Auth-Token:$OS_TOKEN"" -H "Content-Type:application/json" -d '{"project": {"enabled": false}}'http://controller:5000/v3/projects/$PROJECT_ID | python -mjson.tool Enable a project: curl-s -X PATCH -H "X-Auth-Token:$OS_TOKEN"" -H "Content-Type:application/json" -d '{"project": {"enabled": ture}}'http://controller:5000/v3/projects/$PROJECT_ID | python -mjson.tool Create group roleassignment on project: Curl –s –X PUT –H "X-Auth-Token:$OS_TOKEN"http://controller:5000/v3/projects/$PROJECT_ID/groups/$GROUP_ID/roles/$ROLE_ID| python -mjson.tool User Create a user: curl–s -H "X-Auth-Token:$OS_TOKEN" -H "Content-Type:application/json" -d '{"user": {"name":"newuser", "password": "redhat"}}' http://controller:5000/v3/users| python -mjson.tool Show details for auser: curl-s -H "X-Auth-Token:$OS_TOKEN"http://controller:5000/v3/users/$USER_ID | python -mjson.tool Change password(thiscan be done as the user): curl-s -H "X-Auth-Token: $OS_TOKEN" -H "Content-Type: application/json"-d '{ "user": {"password": "'$NEW_PASS'","original_password": "'$ORIG_PASS'"} }'http://controller:5000/v3/users/$USER_ID/password Reset password(thisrequires admin): curl-s -X PATCH -H "X-Auth-Token: $OS_TOKEN" -H "Content-Type: application/json"-d '{ "user": {"password": "'$NEW_PASS'"} }'http://controller:5000/v3/users/$USER_ID | python -mjson.tool
客户端发送HTTP请求流程 1.创建Keystone Client对象。在KeystoneClient对象初始化时,会调用HTTPClient对象的authenticate方法进行用户认证 2.调用Keystone Client对象的tenant_manager成员变量的get方法 Keystone Client对象的tenant_manager成员变量是一个TenantManager对象,TenantManager类继承自ManagerWithFind类,ManagerWithFind类继承自Manager类。Manager类的get方法调用了HTTPClient对象的get方法。 3. HTTPClient对象的get方法实现了发送HTTPGET请求的底层功能
Keystone访问其他服务流程 1.创建Keystone clien对象。通过Keystone Client对象向Keystone服务器发送认证请求,申请用户Token。在用户Token中,可以提取Token ID和服务目录 2.创建需要访问的OpenStack组件的相应Client对象。根据Token中的服务目录,设置Client对象的endpoint等信息 3.当Client对象向OpenStack服务发送HTTP请求时,OpenStack服务会通过auth_token过滤器向Keystone服务器发送认证请求。如果认证成功,OpenStack再调用相应的方法处理用户请求
例:创建虚拟机的流程(含有Neutron)
|