如需转载,请标明原文出处以及作者

陈锐 RuiChen @kiwik

2016/1/30 17:03:16


写在最前面:

这两天遇到一个Nova虚拟机admin密码的问题,顺便理了理当前Nova password相关的逻辑,并对比了一下AWS的实现,于是就有了这篇blog。

API

当前Nova API中和虚拟机password相关的有:

  1. create-instance adminPass参数,用户创建虚拟机时,可以指定密码,不指定时,Nova自动生成。相关配置CONF.enable_instance_password,可以使密码不在创建虚拟机response中返回,除了看不到,其他所有逻辑都没变,如果driver支持,密码还是可以设置成功。
  2. set-admin-password 重置虚拟机密码,当前的XenServer driver和Libvirt KVM/QEMU driver都支持的功能,Libvirt KVM/QEMU是L版本的新增功能,需要1.2.16以上版本的Libvirt。
  3. get-password 获取虚拟机密码,看起来很好理解,实现逻辑有点诡异,实际上当前只有XenServer driver支持,Libvirt KVM/QEMU并不支持。Libvirt不是能set么,不能查么?当前什么都查不到。。。
  4. clear-password 清除当前的虚拟机密码,和上一个一样,XenServer支持,但是在Libvirt下没卵用。
  5. metadata service password metadata API还提供了两个隐藏功能。在虚拟机内部,向 http://169.254.169.254/openstack/latest/password 发送GET请求能查询到当前Nova数据库中保存的password,发送POST请求,可以更新数据库中的password,但是不会影响到虚拟机的当前密码。

为了聚焦核心问题,没有包括:rebuild,evacuate等涉及password的接口。

没想明白Nova的metadata password API该如何使用,如果大家谁知道这个功能的来龙去脉,求指点。

这些API该怎么用

这组password API的逻辑比较古老了,2012年就有修改记录,需要看下内部代码实现细节才能理解。

  1. 创建虚拟机时的adminPass,向下会一直传到nova-compute,然后在生成config driver时,将内容作为meta_data.json的一个属性保存下来。
  2. 不同driver的能力不同,当前只有XenServer driver可以通过接口将adminPass直接设置到虚拟机内,其他driver都搞不了(或依赖文件注入),在driver层也就什么都没做。
  3. XenServer driver设置密码成功之后,会将adminPass用keypairs加密,保存在instance_system_metadata里。
  4. get-password API实现很简单,就是从instance_system_metadata中获取密码返回给用户,但是这个密码是加密的,需要用keypairs的私钥解成明文,安全性的设计上还挺巧妙的,呵呵,这是从AWS那学来的。
  5. clear-password也很简单,就是将instance_system_metadata内容清空,不影响虚拟机的当前密码。

这一套保存密码到instance_system_metadata中的逻辑都是在XenServer driver实现的,所以Libvirt KVM/QEMU driver下adminPass就没有保存,get-password什么都查不到,clear-password也没什么用。个人认为保存密码的逻辑应该在compute manage层实现,当前Libvirt也实现了set-admin-password,所以这里有一两个Blueprint的重构空间。

AWS是怎么玩的

AWS这块细节处理的我觉得还是挺好的。首先创建虚拟机时,不设置adminPass,Linux虚拟机用keypair,Windows虚拟机通过在镜像内预置的EC2Config service插件实现自动生成密码,类似于cloud-init,细节可以参考文档。keypair虽然不是必选参数,但在API文档里着重的强调了没有keypair不能接入虚拟机。这一点很重要,keypair是安全性较高的接入方式,当前大多数的云镜像都默认关闭了ssh password登录,对于Linux虚拟机来说,确实不必舍近求远。

Important If you launch an instance without specifying a key pair, you can’t connect to the instance.

那么Windows虚拟机呢?keypair用来给自动生成的密码加密,然后保存在AWS,不保存用户的明文密码,符合系统安全性要求,用户通过ec2-get-password API获取初始密码,需要同时提供keypair的私钥,将密码解密为明文。有权访问API且拥有私钥的人,才能看到虚拟机密码,安全性也比较高。AWS的文档专门强调ec2-get-password就是用来查询Windows虚拟机密码的。

Linux instances have access to the public key of the key pair at boot. You can use this key to provide secure access to the instance. Amazon EC2 public images use this feature to provide secure access without passwords.

adminPass为什么不生效

Nova创建虚拟机成功之后,我们用返回消息里的adminPass登录虚拟机,然后。。。为什么ssh登录不进去?!

从当前代码实现来看(Liberty版本)不同的driver实现有很大差异,就拿用的最多的libvirt KVM/QEMU,Xen Server和VMWare来看,只有Xen Server driver是直接支持在创建虚拟机时,设置adminPass,不依赖特殊的配置和机制实现;而libvirt KVM/QEMU依赖于文件注入特性,注入adminPass,而VMWare当前就是将adminPass写入config driver,其他什么都没有做。

关于密码注入有一篇blog讲得比较清楚,可以发现如果使用libvirt KVM/QEMU driver,只有开启CONF.libvirt.inject_password并关闭config driver功能才有可能使adminPass生效,还要求镜像格式,lib库满足条件,限制还是很多的,而且将guest的文件系统在host上导出,让人感觉也是不太安全,从这点上看这个功能和keypair相比更是有点鸡肋。

当然上面blog里也提到了一种使用cloud-init的方式使adminPass生效的方法,需要修改cloud-init的源码和配置,patch写的还是不错的,经过我的验证,也可以在libvirt KVM/QEMU driver下生效,但是我一直没有找到这个patch的出处,当前最新的cloud-init版本(0.7.7)也没有合入这个patch,所以修改cloud-init源码的方式用起来还是非常的不方便。

还有其他的玩法么

说实话上边的这些实现都不能使我满意,回到问题的最本质,其实就是想要“设置虚拟机的初始密码”,那么adminPass是唯一的方式么?

大家可能都注意到了,不管哪种类型的driver,adminPass都被写入了config driver中,如果cloud-init可以消费config driver中的adminPass,然后在虚拟机第一次启动的时候,通过cloud-init使密码生效,看起来是一种比较好的方式,但是不知道cloud-init在哪个版本可能实现。这里有个cloud-init的bug跟踪这个问题。

翻了翻blog,发现一种当前可行的替代方案,用cloud-init+user_data设置密码,完全不用adminPass。

当前大多数的云镜像都已经集成了cloud-init,而且cloud-init也有设置用户密码的功能,用法很简单,将如下代码片段保存在一个文本文件中,例如:cloud-config.txt,注意第一行的#cloud-config不能省略,然后通过下面的命令启动虚拟机:

nova --image xxx --flavor xxx --nic net-id=xxx --user-data cloud-config.txt cloud_vm

#cloud-config
password: cloud
chpasswd: { expire: False }
ssh_pwauth: True

由于cloud-init修改的是默认用户的密码,因此ssh登录的时候使用默认的云镜像用户,ubuntu镜像是ubuntu用户,fedora镜像是fedora用户,然后输入cloud-config password字段配置的密码就可以了,例如:

ssh ubuntu@10.0.0.12

cloud-config还有许多其他的高级功能,可以参考cloud-config example

两点建议

  1. 要keypair,不要password
  2. 要cloud-init,不要文件注入


Published

30 January 2016

Category

OpenStack

Tags