Fernet Token in Keystone v3 (by quqi99)

标签: fernetkeystone
2110人阅读 评论(1) 收藏 举报
分类:

**作者:张华 发表于:2016-08-11
版权声明:可以任意转载,转载时请务必以超链接形式标明文章原始出处和作者信息及本版权声明
( http://blog.csdn.net/quqi99 )**

问题的由来

keystone中使用token的过程
- UUID: nova client通过user/pass从keystone获取UUID Token(UUID为一段32位字符串),nova client还得再拿UUID去keystone端验证token是否有效(有效期,用户组,服务目录等元数据信息存储在DB中),这样keystone的压力很大,另外由于需要持久化token所以token在不同region之间同步也是一个问题。
- PKI: client通过user/pass从keystone获取PKI Token(包括了元数据信息, keystone会只用私钥对其进行签名和CMS编码,没有加密),nova client不需要再去keystone端验证, nova能直接解码得到token的有效性等元数据信息,故nova不需要再请求keystone来验证这个Token,它省略了上图中的步骤4能大大减轻keystone的压力。但缺点是它的长度容易超过WEB Server对HTTP HEADER长度的限制, 且同样需要持久化token。
- PZKI: PKI的长度容易超过WEB Server对HTTP HEADER长度的限制,于是PZKI通过zlib来对token进行压缩。它只解决了token过长的问题,仍然没有解决持久化token带来的问题。
- Fernet: fernet使用AES-CBC来对称加密并使用SHA256来签名token,token只能通过对称密钥读取和更改,不需要持久化token,对于多个keystone节点的region之间的部署,只需要将相同的key发布到所有节点上,那么无论是通过哪个节点生成的token,都可以被其他的keystone节点所验证。用户在部署时所要考虑的,就是如何在Fernet Key Rotate的时候保持所有节点上key repository的同步,而这远远要比同步上万条token纪录来的简单。且fernet token只加密必要的信息,长度一般不超过255字节,避免了PKI token过大的问题。

Fernet Key Format

Fernet Key是由下列字段组合的base64编码(base64.urlsafe_b64encode):

  • 8 bits, Fernet Format Version(0x80)
  • 64 bits, current timestamp, int(time.time())
  • 128 bits, Initailization Vector(IV), os.urandom(16)
  • Ciphertext(Version, User_ID, Methods, Project_ID, Expiration Time, Audit IDs)
  • 256 bits, SHA256 HMAC with signing key

Fernet Key Rotation

可以通过max_active_keys=3配置在/etc/keystone/fernet-keys目录生成至多3个key, 数字最大的叫Primary Key, 其次大的叫Secondary Key, 再其次大的叫Staged Key。keystone使用Primary Key加密,可使用所有的Key按2,1,0的顺序进行解密和验证。

  • 默认使用keystone-manage utility初始化/etc/keystone/fernet-keys目录时,1为Primar Key, 0为Stage Key,没有Secondary Key.
  • Fernet Key Rotation后,以前的0变成2成为Primary Key, 以前的1还是1作为Secondary Key, 新生成0作为Staged Key
  • 再次Fernet Key Rotation后,0 becomes 3, 1 gets deleted, 2 stays 2, a new key becomes 0
  • 两个region不需要同时进行Fernet Key Rotation, 因为keystone使用Primary Key加密,使用所有的Key按2,1,0的顺序进行解密和验证。不需要sync token,但是需要sync token repository, 这样就能使一个node生成的tokens可以立即被其他节点验证。

快速测试

1, 采用juju快速部署测试环境:

$ juju-deployer -c ./keystone-v3.yaml -d xenial-mitaka
$ cat keystone-v3.yaml
keystone-v3:
  services:
    keystone:
      branch: https://github.com/openstack/charm-keystone
      num_units: 1
      options:
        preferred-api-version: 3
        admin-password: 'password'
        admin-token: 'ubuntutesting'
        debug: 'true'
        verbose: 'true'
    mysql:
      branch: https://github.com/openstack/charm-percona-cluster
      constraints: mem=1G
      num_units: 1
      options:
        dataset-size: '50%'
        root-password: 'password'
        sst-password: 'password'
  relations:
    - [ keystone, mysql ]
xenial-mitaka:
  inherits: keystone-v3
  series: xenial

2, 更新keystone.conf

[token]
#provider = keystone.token.providers.uuid.Provider
provider = fernet

3, 更新DB

su -s /bin/sh -c "keystone-manage db_sync" keystone

4, Initiate fernet key repository

mkdir -p /etc/keystone/fernet-keys
chown -R keystone:keystone /etc/keystone/fernet-keys
keystone-manage fernet_setup --keystone-user keystone --keystone-group keystone

5, restart apache2

cat /etc/apache2/sites-enabled/wsgi-keystone.conf
systemctl restart apache2

6, Verify

export OS_TOKEN=ubuntutesting
export OS_URL=${OS_AUTH_PROTOCOL:-http}://`juju-deployer -f keystone`:5000/v3
export OS_IDENTITY_API_VERSION=3

openstack service create --name keystone --description "OpenStack Identity" identity
openstack service list

openstack endpoint create --region RegionOne identity public http://`juju-deployer -f keystone`:5000/v3
openstack endpoint create --region RegionOne identity internal http://`juju-deployer -f keystone`:5000/v3
openstack endpoint create --region RegionOne identity admin http://`juju-deployer -f keystone`:35357/v3
openstack endpoint list

openstack domain create --description "Default Domain" default
openstack domain list

openstack project create --domain default --description "Admin Project" admin
openstack project create --domain default --description "Service Project" services
openstack project list

openstack role create admin
openstack role create user
openstack role list

openstack user create --domain default --password-prompt admin
openstack role add --project admin --user admin admin
openstack user create --domain default --password-prompt demo
openstack role add --project services --user demo user
openstack user list

#Verify Token
cat > demo-openrc << OFF
export OS_PROJECT_DOMAIN_NAME=default
export OS_USER_DOMAIN_NAME=default
export OS_PROJECT_NAME=services
export OS_USERNAME=demo
export OS_PASSWORD=password
export OS_AUTH_URL=http://`juju-deployer -f keystone`:5000/v3
export OS_IDENTITY_API_VERSION=3
export OS_IMAGE_API_VERSION=2
OFF
source ./demo-openrc
unset OS_TOKEN OS_URL
openstack token issue

#Get Token
cat > token-request.json << OFF
{
  "auth": {
    "identity": {
      "methods": [
        "password"
      ],
      "password": {
        "user": {
          "domain": {
            "name": "default"
          },
          "name": "demo",
          "password": "password"
        }
      }
    }
  }
}
OFF
USER_ID=$(curl -d @token-request.json -H "Content-type: application/json" http://`juju-deployer -f keystone`:5000/v3/auth/tokens | python -c "import sys; import json; tok = json.loads(sys.stdin.read()); print tok['token']['user']['id'];")

TOKEN=$(curl -i -d @token-request.json -H "Content-type: application/json" http://`juju-deployer -f keystone`:5000/v3/auth/tokens |grep X-Subject-Token |awk -F ':' '{print $2}') 

#Use Token
curl -H "X-Auth-Token: $TOKEN" http://`juju-deployer -f keystone`:5000/v2.0/tenants

Fernet Key in Multiple Regions

Fernet Key in multiple regions
1, 需要创建第二个keystone作为RegionTwo

openstack endpoint create \
--publicurl http://controller:5000/v2.0 \
--internalurl http://controller:5000/v2.0 \
--adminurl http://controller:35357/v2.0 \
--region RegionTwo \
identity

2, 这些Keystone Region Nodes所使用的DB应该sync
3, 上面fernet_setup命令生成的fernet key初始时应该复制到所有Keystone region nodes.
4, Key rotate

keystone-manage fernet_rotate --keystone-user keystone --keystone-group keystone
ls /etc/keystone/fernet-keys/

Key Rotation
5, token不需要sync,但fernet key repository应该在所有keystone region nodes间作sync。例:

rsync -e 'ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no' \
          -avz \
          --delete \
          {{ keystone_fernet_tokens_key_repository }}/ \
          {{ keystone_system_user_name }}@{{ hostvars[host]['ansible_ssh_host'] }}:{{ keystone_fernet_tokens_key_repository }}/

Appendix - Keystone v3

  1. configurations`[service_credentials]
    auth_url = http://xxxx:5000/v3
    username = ceilometer
    tenant_name = service
    password = xxxxxx
    project_name = service
    project_domain_name = default
    user_domain_name = default
    auth_type = password

[keystone_authtoken]
auth_plugin = password
auth_url = http://192.168.200.178:35357
auth_uri=http://192.168.200.178:5000
username = ceilometer
password = xxxxx
project_name = services
user_domain_name = default
project_domain_name = default
2. env variables

export OS_PROJECT_DOMAIN_NAME=default
export OS_USER_DOMAIN_NAME=default
export OS_AUTH_URL=http://[2001:2:3:4500:fa32:e4ff:febe:87cd]:5000/v3
export OS_PROJECT_NAME=services
export OS_USERNAME=demo
export OS_PASSWORD=password
export OS_IDENTITY_API_VERSION=3
export OS_IMAGE_API_VERSION=2
3.
from keystoneauth1.identity import v3
from keystoneauth1 import session
from keystoneclient.v3 import client
auth = v3.Password(auth_url=’http://10.5.8.27:5000/v3‘,
username=’ceilometer’,
password=’xxx’,
project_name=’services’,
user_domain_name=’default’,
project_domain_name=’default’)
sess = session.Session(auth=auth)
keystone = client.Client(session=sess)
tenants = keystone.projects.list()
4.
TOKEN=$(curl -i -H “Content-Type: application/json” -d ’
{ “auth”: {
“identity”: {
“methods”: [“password”],
“password”: {
“user”: {
“name”: “ceilometer”,
“domain”: { “name”: “default” },
“password”: “xxx”
}
}
}
}
}’ http://10.5.8.27:5000/v3/auth/tokens |grep X-Subject-Token |awk -F ‘:’ ‘{print $2}’)
curl -g -X GET http://10.5.8.27:35357/v3/auth/projects -H “Accept: application/json” -H “X-Auth-Token: $TOKEN” | python -m json.tool
5.
openstack domain list –os-identity-api-version 3 –os-token ubuntutesting –os-url http://10.5.7.210:35357/v3
openstack token issue –os-username ceilometer –os-project-name services –os-auth-url http://10.5.7.210:5000/v3 –os-password xxx –os-user-domain-name default –os-project-domain-name default
`

参考

[1] https://developer.ibm.com/opentech/2015/11/11/deep-dive-keystone-fernet-tokens
[2] http://blog.csdn.net/zjluobing/article/details/51492356
[3] http://dolphm.com/inside-openstack-keystone-fernet-token-payloads/
[4] https://github.com/openstack/openstack-ansible-os_keystone/blob/master/templates/keystone-fernet-rotate.sh.j2
[5] http://gogosatellite.blogspot.jp/2016/05/openstack-keystone-fernet-key-in.html
[6] https://bugs.launchpad.net/keystone/+bug/1338550

1
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:1395961次
    • 积分:15843
    • 等级:
    • 排名:第661名
    • 原创:295篇
    • 转载:10篇
    • 译文:0篇
    • 评论:298条