Dear guys I encountered a problem that a ssh public key of ssh_keypairs for a newly created instance is overridden by another ssh key in template meta data. I think this leads to security vulnerability because a template owner can login to other user's instance created from the template. So, could you fix this issue?
This behavior is caused by meta data import at commitUserVm method. A ssh key value specified by an instance owner is set to a UserVmVO object at line 2986-2988 of server/src/com/cloud/vm/UserVmManagerImpl.java in 4.3 branch [1], but this value is overridden at line 3035-3038 by template meta data. Please note a database contains meta data entries related to a template which you created from an instance in cloud.template_view like [2]. 2nd row has detail_name and detail_value about ssh key and CloudStack override the user specified ssh key value by the owner's detail value in this situation. It results in delivery of the template owner's ssh key for the instance created from the template to virtual router inspite of specification of instance owner's ssh key. You can reproduce this phenomenon like below. 1. Deploy an instance with a ssh key A by specifying 'keypair' value. 2. Create a template from this instance. 3. Deploy an instance with another ssh key B by specifying 'keypair' value. [1] server/src/com/cloud/vm/UserVmManagerImpl.java 2971 private UserVmVO commitUserVm(final DataCenter zone, final VirtualMachineTemplate template, final String hostName, final String displayName, final Account owner, 2972 final Long diskOfferingId, final Long diskSize, final String userData, final HypervisorType hypervisor, final Account caller, final Boolean isDisplayVmEnabled, 2973 final String keyboard, final long accountId, final ServiceOfferingVO offering, final boolean isIso, final String sshPublicKey, 2974 final LinkedHashMap<String, NicProfile> networkNicMap, final long id, final String instanceName, final String uuidName, final HypervisorType hypervisorType, 2975 final Map<String, String> customParameters) throws InsufficientCapacityException { 2976 return Transaction.execute(new TransactionCallbackWithException<UserVmVO, InsufficientCapacityException>() { 2977 @Override 2978 public UserVmVO doInTransaction(TransactionStatus status) throws InsufficientCapacityException { 2979 UserVmVO vm = new UserVmVO(id, instanceName, displayName, 2980 template.getId(), hypervisorType, template.getGuestOSId(), 2981 offering.getOfferHA(), offering.getLimitCpuUse(), 2982 owner.getDomainId(), owner.getId(), offering.getId(), userData, 2983 hostName, diskOfferingId); 2984 vm.setUuid(uuidName); 2985 vm.setDynamicallyScalable(template.isDynamicallyScalable()); 2986 if (sshPublicKey != null) { 2987 vm.setDetail("SSH.PublicKey", sshPublicKey); 2988 } 2989 2990 if (keyboard != null && !keyboard.isEmpty()) 2991 vm.setDetail(VmDetailConstants.KEYBOARD, keyboard); 2992 2993 if (isIso) { 2994 vm.setIsoId(template.getId()); 2995 } 2996 2997 if(isDisplayVmEnabled != null){ 2998 if(!_accountMgr.isRootAdmin(caller.getType())){ 2999 throw new PermissionDeniedException( "Cannot update parameter displayvm, only admin permitted "); 3000 } 3001 vm.setDisplayVm(isDisplayVmEnabled); 3002 }else { 3003 vm.setDisplayVm(true); 3004 } 3005 3006 // If hypervisor is vSphere, check for clone type setting. 3007 if (hypervisorType.equals(HypervisorType.VMware)) { 3008 // retrieve clone flag. 3009 UserVmCloneType cloneType = UserVmCloneType.linked; 3010 String value = _configDao.getValue(Config.VmwareCreateFullClone.key()); 3011 if (value != null) { 3012 if (Boolean.parseBoolean(value) == true) 3013 cloneType = UserVmCloneType.full; 3014 } 3015 UserVmCloneSettingVO vmCloneSettingVO = new UserVmCloneSettingVO(id, cloneType.toString()); 3016 _vmCloneSettingDao.persist(vmCloneSettingVO); 3017 } 3018 3019 long guestOSId = template.getGuestOSId(); 3020 GuestOSVO guestOS = _guestOSDao.findById(guestOSId); 3021 long guestOSCategoryId = guestOS.getCategoryId(); 3022 GuestOSCategoryVO guestOSCategory = _guestOSCategoryDao.findById(guestOSCategoryId); 3023 3024 3025 // If hypervisor is vSphere and OS is OS X, set special settings. 3026 if (hypervisorType.equals(HypervisorType.VMware)) { 3027 if (guestOS.getDisplayName().toLowerCase().contains("apple mac os")){ 3028 vm.setDetail("smc.present", "TRUE"); 3029 vm.setDetail(VmDetailConstants.ROOK_DISK_CONTROLLER, "scsi"); 3030 vm.setDetail("firmware", "efi"); 3031 s_logger.info("guestOS is OSX : overwrite root disk controller to scsi, use smc and efi"); 3032 } 3033 } 3034 3035 Map<String, String> details = template.getDetails(); 3036 if ( details != null && !details.isEmpty() ) { 3037 vm.details.putAll(details); 3038 } 3039 3040 _vmDao.persist(vm); 3041 if (customParameters != null && customParameters.size() > 0) { 3042 for (String key : customParameters.keySet()) { 3043 vm.setDetail(key, customParameters.get(key)); 3044 } 3045 } 3046 _vmDao.saveDetails(vm); [2] database example mysql> select * from cloud.template_view where id=207 \G; *************************** 1. row *************************** id: 207 uuid: c96f0d9a-0a56-4d30-af73-fe8b31ae37c3 unique_name: 2219faa5a-4e7b-3425-b6e6-135ab210422b name: cluster_frontend-20140520.2 public: 1 featured: 0 type: USER hvm: 1 bits: 64 url: NULL format: QCOW2 created: 2014-05-20 09:33:47 checksum: NULL display_text: Cluster Frontend VM CentOS 6.5 ver.20140520.2 enable_password: 1 dynamically_scalable: 0 template_state: Active guest_os_id: 182 guest_os_uuid: 9d3c42d8-caab-11e3-9125-001e679910a0 guest_os_name: CentOS 6.4 (64-bit) bootable: 1 prepopulate: 0 cross_zones: 0 hypervisor_type: KVM extractable: 0 template_tag: NULL sort_key: 0 removed: NULL enable_sshkey: 0 source_template_id: 205 source_template_uuid: c131680c-3e0e-4d7c-b554-02dabc10ade1 account_id: 3 account_uuid: f9e4e1ca-69fd-4ae3-b70c-15bbcc13406e account_name: sgcadm account_type: 0 domain_id: 2 domain_uuid: 84dd635d-fb99-4895-b199-7d777aa144d5 domain_name: default domain_path: /default/ project_id: NULL project_uuid: NULL project_name: NULL data_center_id: NULL data_center_uuid: NULL data_center_name: NULL lp_account_id: NULL store_id: 3 store_scope: REGION state: Ready download_state: DOWNLOADED download_pct: 100 error_str: NULL size: 18465816576 destroyed: 0 created_on_store: 2014-05-20 09:33:47 detail_name: Message.ReservedCapacityFreed.Flag detail_value: false tag_id: NULL tag_uuid: NULL tag_key: NULL tag_value: NULL tag_domain_id: NULL tag_account_id: NULL tag_resource_id: NULL tag_resource_uuid: NULL tag_resource_type: NULL tag_customer: NULL temp_zone_pair: 207_0 *************************** 2. row *************************** id: 207 uuid: c96f0d9a-0a56-4d30-af73-fe8b31ae37c3 unique_name: 2219faa5a-4e7b-3425-b6e6-135ab210422b name: cluster_frontend-20140520.2 public: 1 featured: 0 type: USER hvm: 1 bits: 64 url: NULL format: QCOW2 created: 2014-05-20 09:33:47 checksum: NULL display_text: Cluster Frontend VM CentOS 6.5 ver.20140520.2 enable_password: 1 dynamically_scalable: 0 template_state: Active guest_os_id: 182 guest_os_uuid: 9d3c42d8-caab-11e3-9125-001e679910a0 guest_os_name: CentOS 6.4 (64-bit) bootable: 1 prepopulate: 0 cross_zones: 0 hypervisor_type: KVM extractable: 0 template_tag: NULL sort_key: 0 removed: NULL enable_sshkey: 0 source_template_id: 205 source_template_uuid: c131680c-3e0e-4d7c-b554-02dabc10ade1 account_id: 3 account_uuid: f9e4e1ca-69fd-4ae3-b70c-15bbcc13406e account_name: sgcadm account_type: 0 domain_id: 2 domain_uuid: 84dd635d-fb99-4895-b199-7d777aa144d5 domain_name: default domain_path: /default/ project_id: NULL project_uuid: NULL project_name: NULL data_center_id: NULL data_center_uuid: NULL data_center_name: NULL lp_account_id: NULL store_id: 3 store_scope: REGION state: Ready download_state: DOWNLOADED download_pct: 100 error_str: NULL size: 18465816576 destroyed: 0 created_on_store: 2014-05-20 09:33:47 detail_name: SSH.PublicKey detail_value: ssh-rsa ...(snip) tag_id: NULL tag_uuid: NULL tag_key: NULL tag_value: NULL tag_domain_id: NULL tag_account_id: NULL tag_resource_id: NULL tag_resource_uuid: NULL tag_resource_type: NULL tag_customer: NULL temp_zone_pair: 207_0 *************************** 3. row *************************** id: 207 uuid: c96f0d9a-0a56-4d30-af73-fe8b31ae37c3 unique_name: 2219faa5a-4e7b-3425-b6e6-135ab210422b name: cluster_frontend-20140520.2 public: 1 featured: 0 type: USER hvm: 1 bits: 64 url: NULL format: QCOW2 created: 2014-05-20 09:33:47 checksum: NULL display_text: Cluster Frontend VM CentOS 6.5 ver.20140520.2 enable_password: 1 dynamically_scalable: 0 template_state: Active guest_os_id: 182 guest_os_uuid: 9d3c42d8-caab-11e3-9125-001e679910a0 guest_os_name: CentOS 6.4 (64-bit) bootable: 1 prepopulate: 0 cross_zones: 0 hypervisor_type: KVM extractable: 0 template_tag: NULL sort_key: 0 removed: NULL enable_sshkey: 0 source_template_id: 205 source_template_uuid: c131680c-3e0e-4d7c-b554-02dabc10ade1 account_id: 3 account_uuid: f9e4e1ca-69fd-4ae3-b70c-15bbcc13406e account_name: sgcadm account_type: 0 domain_id: 2 domain_uuid: 84dd635d-fb99-4895-b199-7d777aa144d5 domain_name: default domain_path: /default/ project_id: NULL project_uuid: NULL project_name: NULL data_center_id: NULL data_center_uuid: NULL data_center_name: NULL lp_account_id: NULL store_id: 3 store_scope: REGION state: Ready download_state: DOWNLOADED download_pct: 100 error_str: NULL size: 18465816576 destroyed: 0 created_on_store: 2014-05-20 09:33:47 detail_name: Encrypted.Password detail_value: ...(snip) tag_id: NULL tag_uuid: NULL tag_key: NULL tag_value: NULL tag_domain_id: NULL tag_account_id: NULL tag_resource_id: NULL tag_resource_uuid: NULL tag_resource_type: NULL tag_customer: NULL temp_zone_pair: 207_0 3 rows in set (0.00 sec) ERROR: No query specified mysql> Best Regards -- Hiroki Ohashi