U
    L¬÷d‡;  ã                
   @   sÀ  U d Z ddlZddlZddlZddlZddlZddlmZ ddlm	Z	m
Z
mZ ddlmZmZmZ ddlmZ ddlmZ ddlmZmZ dd	lmZmZ dd
lmZ dZdddeegeedƒgg dœZeed< eeƒZ e e ¡Z!ddddgZ"ddgZ#e $d¡Z%dZ&dZ'dgZ(i Z)i Z*e"D ]fZ+e) ,e+› de&e+ dfe+› de&e+ › ddfe+› de&e+ › ddfi¡ e+› de*e+› d< qd Z-e.eee/dd!œd"d#„Z0d$d%„ Z1d)e
ee.  d&œd'd(„Z2dS )*zSSH: Configure SSH and SSH keysé    N)Údedent)ÚListÚOptionalÚSequence)Ússh_utilÚsubpÚutil)ÚCloud)ÚConfig)Ú
MetaSchemaÚget_meta_doc)ÚALL_DISTROSÚug_util)ÚPER_INSTANCEaÂ  This module handles most configuration for SSH and both host and authorized SSH
keys.

**Authorized keys**

Authorized keys are a list of public SSH keys that are allowed to connect to
a user account on a system. They are stored in `.ssh/authorized_keys` in that
account's home directory. Authorized keys for the default user defined in
``users`` can be specified using ``ssh_authorized_keys``. Keys
should be specified as a list of public keys.

.. note::
    See the ``cc_set_passwords`` module documentation to enable/disable SSH
    password authentication.

Root login can be enabled/disabled using the ``disable_root`` config key. Root
login options can be manually specified with ``disable_root_opts``.

Supported public key types for the ``ssh_authorized_keys`` are:

    - dsa
    - rsa
    - ecdsa
    - ed25519
    - ecdsa-sha2-nistp256-cert-v01@openssh.com
    - ecdsa-sha2-nistp256
    - ecdsa-sha2-nistp384-cert-v01@openssh.com
    - ecdsa-sha2-nistp384
    - ecdsa-sha2-nistp521-cert-v01@openssh.com
    - ecdsa-sha2-nistp521
    - sk-ecdsa-sha2-nistp256-cert-v01@openssh.com
    - sk-ecdsa-sha2-nistp256@openssh.com
    - sk-ssh-ed25519-cert-v01@openssh.com
    - sk-ssh-ed25519@openssh.com
    - ssh-dss-cert-v01@openssh.com
    - ssh-dss
    - ssh-ed25519-cert-v01@openssh.com
    - ssh-ed25519
    - ssh-rsa-cert-v01@openssh.com
    - ssh-rsa
    - ssh-xmss-cert-v01@openssh.com
    - ssh-xmss@openssh.com

.. note::
    this list has been filtered out from the supported keytypes of
    `OpenSSH`_ source, where the sigonly keys are removed. Please see
    ``ssh_util`` for more information.

    ``dsa``, ``rsa``, ``ecdsa`` and ``ed25519`` are added for legacy,
    as they are valid public keys in some old distros. They can possibly
    be removed in the future when support for the older distros are dropped

.. _OpenSSH: https://github.com/openssh/openssh-portable/blob/master/sshkey.c

**Host keys**

Host keys are for authenticating a specific instance. Many images have default
host SSH keys, which can be removed using ``ssh_deletekeys``.

Host keys can be added using the ``ssh_keys`` configuration key.

When host keys are generated the output of the ssh-keygen command(s) can be
displayed on the console using the ``ssh_quiet_keygen`` configuration key.

.. note::
    When specifying private host keys in cloud-config, care should be taken to
    ensure that the communication between the data source and the instance is
    secure.


If no host keys are specified using ``ssh_keys``, then keys will be generated
using ``ssh-keygen``. By default one public/private pair of each supported
host key type will be generated. The key types to generate can be specified
using the ``ssh_genkeytypes`` config flag, which accepts a list of host key
types to use. For each host key type for which this module has been instructed
to create a keypair, if a key of the same type is already present on the
system (i.e. if ``ssh_deletekeys`` was false), no key will be generated.

Supported host key types for the ``ssh_keys`` and the ``ssh_genkeytypes``
config flags are:

    - dsa
    - ecdsa
    - ed25519
    - rsa

Unsupported host key types for the ``ssh_keys`` and the ``ssh_genkeytypes``
config flags are:

    - ecdsa-sk
    - ed25519-sk
Zcc_sshZSSHzConfigure SSH and SSH keysa              ssh_keys:
              rsa_private: |
                -----BEGIN RSA PRIVATE KEY-----
                MIIBxwIBAAJhAKD0YSHy73nUgysO13XsJmd4fHiFyQ+00R7VVu2iV9Qco
                ...
                -----END RSA PRIVATE KEY-----
              rsa_public: ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAGEAoPRhIfLvedSDKw7Xd ...
              rsa_certificate: |
                ssh-rsa-cert-v01@openssh.com AAAAIHNzaC1lZDI1NTE5LWNlcnQt ...
              dsa_private: |
                -----BEGIN DSA PRIVATE KEY-----
                MIIBxwIBAAJhAKD0YSHy73nUgysO13XsJmd4fHiFyQ+00R7VVu2iV9Qco
                ...
                -----END DSA PRIVATE KEY-----
              dsa_public: ssh-dsa AAAAB3NzaC1yc2EAAAABIwAAAGEAoPRhIfLvedSDKw7Xd ...
              dsa_certificate: |
                ssh-dsa-cert-v01@openssh.com AAAAIHNzaC1lZDI1NTE5LWNlcnQt ...
            ssh_authorized_keys:
              - ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAGEA3FSyQwBI6Z+nCSjUU ...
              - ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA3I7VUf2l5gSn5uavROsc5HRDpZ ...
            ssh_deletekeys: true
            ssh_genkeytypes: [rsa, dsa, ecdsa, ed25519]
            disable_root: true
            disable_root_opts: no-port-forwarding,no-agent-forwarding,no-X11-forwarding
            allow_public_ssh_keys: true
            ssh_quiet_keygen: true
            ssh_publish_hostkeys:
              enabled: true
              blacklist: [dsa]
            )ÚidÚnameÚtitleZdescriptionZdistrosZ	frequencyZexamplesZactivate_by_schema_keysÚmetaZrsaZdsaZecdsaZed25519z4^(ecdsa-sk|ed25519-sk)_(private|public|certificate)$z/etc/ssh/ssh_host_%s_keyTZ_privateé€  Z_publicú.pubé¤  Ú_certificatez	-cert.pubz;o=$(ssh-keygen -yf "%s") && echo "$o" root@localhost > "%s")r   ÚcfgÚcloudÚargsÚreturnc           (      C   sä  |  dd¡r\tj dd¡}t |¡D ]6}zt |¡ W q$ tk
rX   t t	d|¡ Y q$X q$d|krÈg }|d  
¡ D ]t\}}|tkrªt |¡r–d}	nd}	t	 d	|	|¡ qvt| d
 }
t| d }t |
||¡ d|krv| dt|
ƒf¡ qv|rút |¡ t 
¡ D ]À\}}||d ks||d kr*qt| d
 t| d
  }}ddt||f g}z:tjddd tj|dd W 5 Q R X t	 d||¡ W n. tk
r¾   t t	d|› d|› ¡ Y nX qnÞt |dt¡}t ¡ sä|ndd„ |D ƒ}t|ƒ |¡}|rt	 dd |¡¡ tj ¡ }d|d< |D ]t}t | }tj !|¡rNq.t "tj #|¡¡ dd|d d!d"|g}tjddd z¢tj|d|d#\}}t $|d$d¡s¼t%j& 't (|¡¡ t )d¡}|d%kr$d&}t *¡ }|rø|t +d'd
¡k rød(}t ,|d%|¡ t -||¡ t -|› d)d*¡ W np tj.k
r– } zNt (|j/¡ 0¡ }|j1dkrv| 0¡  2d+¡rvt	 d,|¡ nt t	d-||¡ W 5 d }~X Y nX W 5 Q R X q.d.|krÖt |d. d/t3¡}t $|d. d0t4¡}nt3}t4}|r"t5|d1}z|j6 7|¡ W n" tk
r    t t	d2¡ Y nX zšt8 9||j:¡\} }!t8 ;| ¡\}"}#t $|d3d¡}$t <|d4tj=¡}%g }&t $|d5d¡r†| >¡ p‚g }&n
t	 d6¡ d7|kr¬|d7 }'|& ?|'¡ t@|&|"|$|%ƒ W n" tk
rÞ   t t	d8¡ Y nX d S )9NZssh_deletekeysTz	/etc/ssh/zssh_host_*key*zFailed deleting key file %sZssh_keysZunsupportedZunrecognizedz Skipping %s ssh_keys entry: "%s"r   é   r   ZHostCertificateZshz-xcz/etc/ssh)Ú	recursiveF)ÚcapturezGenerated a key for %s from %szFailed generating a key for z from Zssh_genkeytypesc                 S   s   g | ]}|t kr|‘qS © )ÚFIPS_UNSUPPORTED_KEY_NAMES)Ú.0Únamesr   r   ú9/usr/lib/python3/dist-packages/cloudinit/config/cc_ssh.pyÚ
<listcomp>	  s   þzhandle.<locals>.<listcomp>z5skipping keys that are not supported in fips mode: %sú,ÚCZLANGz
ssh-keygenz-tz-NÚ z-f)r   ÚenvZssh_quiet_keygenéÿÿÿÿr   é	   i   r   r   zunknown keyz!ssh-keygen: unknown key type '%s'z(Failed generating key type %s to file %sZssh_publish_hostkeysÚ	blacklistÚenabled©r+   zPublishing host keys failed!Údisable_rootÚdisable_root_optsZallow_public_ssh_keyszSSkipping import of publish SSH keys per config setting: allow_public_ssh_keys=FalseZssh_authorized_keysz Applying SSH credentials failed!)AÚgetÚosÚpathÚjoinÚglobr   Zdel_fileÚ	ExceptionZlogexcÚLOGÚitemsÚCONFIG_KEY_TO_FILEÚpattern_unsupported_config_keysÚmatchZwarningZ
write_fileÚappendÚstrr   Zappend_ssh_configÚPRIV_TO_PUBÚKEY_GEN_TPLZSeLinuxGuardr   ÚdebugZget_cfg_option_listÚGENERATE_KEY_NAMESZfips_enabledÚsetÚ
differenceÚenvironÚcopyÚKEY_FILE_TPLÚexistsZ
ensure_dirÚdirnameZget_cfg_option_boolÚsysÚstdoutÚwriteZdecode_binaryZget_group_idZget_opensshd_upstream_versionZVersionÚchownÚchmodZProcessExecutionErrorÚstderrÚlowerZ	exit_codeÚ
startswithÚHOST_KEY_PUBLISH_BLACKLISTÚPUBLISH_HOST_KEYSÚget_public_host_keysZ
datasourceZpublish_host_keysr   Znormalize_users_groupsZdistroZextract_defaultZget_cfg_option_strZDISABLE_USER_OPTSZget_public_ssh_keysÚextendÚapply_credentials)(r   r   r   r   Zkey_pthÚfZcert_configÚkeyÚvalÚreasonZtgt_fnZ	tgt_permsZprivate_typeZpublic_typeZprivate_fileZpublic_fileÚcmdZgenkeysZ	key_namesZskipped_keysZlang_cZkeytypeZkeyfileÚoutÚerrÚgidZpermissions_privateZssh_versionÚeZhost_key_blacklistZpublish_hostkeysZhostkeysZusersZ_groupsÚuserZ_user_configr.   r/   ÚkeysZcfgkeysr   r   r#   ÚhandleÈ   s   



ÿ
þ

þ  ÿþ  ÿÿþý	þ

  ÿ

ÿü$
ý  ÿ
  ÿÿ

r`   c                 C   sV   t | ƒ} |rt | |¡ |r>|s$d}| d|¡}| dd¡}nd}tj| d|d d S )NZNONEz$USERz$DISABLE_USERÚrootr'   )Zoptions)rA   r   Zsetup_user_keysÚreplace)r_   r^   r.   r/   Z
key_prefixr   r   r#   rT   n  s    rT   r-   c                    sŠ   dt f ‰g }g ‰ | r(‡fdd„| D ƒ‰ ‡ fdd„t ˆd ¡D ƒ}|D ]<}t |¡}| ¡ }|rHt|ƒdkrH| t|dd… ƒ¡ qH|S )	a  Read host keys from /etc/ssh/*.pub files and return them as a list.

    @param blacklist: List of key types to ignore. e.g. ['dsa', 'rsa']
    @returns: List of keys, each formatted as a two-element tuple.
        e.g. [('ssh-rsa', 'AAAAB3Nz...'), ('ssh-ed25519', 'AAAAC3Nx...')]
    z%s.pubc                    s   g | ]}ˆ |f ‘qS r   r   )r!   Zkey_type)Úpublic_key_file_tmplr   r#   r$   Œ  s    z(get_public_host_keys.<locals>.<listcomp>c                    s   g | ]}|ˆ kr|‘qS r   r   )r!   Zhostfile)Úblacklist_filesr   r#   r$     s   þ)Ú*r   Né   )rE   r4   r   Z	load_fileÚsplitÚlenr;   Útuple)r+   Zkey_listZ	file_listÚ	file_nameZfile_contentsZkey_datar   )rd   rc   r#   rR     s     

ÿ
þ
rR   )N)3Ú__doc__r4   Zloggingr1   ÚrerH   Útextwrapr   Útypingr   r   r   Z	cloudinitr   r   r   Zcloudinit.cloudr	   Zcloudinit.configr
   Zcloudinit.config.schemar   r   Zcloudinit.distrosr   r   Zcloudinit.settingsr   ZMODULE_DESCRIPTIONr   Ú__annotations__Z	getLoggerÚ__name__r6   r@   r    Úcompiler9   rE   rQ   rP   r8   r=   ÚkÚupdater>   r<   Úlistr`   rT   rR   r   r   r   r#   Ú<module>   sl   eÿÿ#Ö-
ÿ 
  ýÿ '