← Back to team overview

cloud-init-dev team mailing list archive

Re: [Merge] ~illfelder/cloud-init:master into cloud-init:master

 

givin config 'cfg' and distro 'distro'

  (users, _groups) = ug_util.normalize_users_groups(cfg, distro)
  (default_user, _user_config) = ug_util.extract_default(users)

default_user is then the use name.

I think there may be an issue though in that the cfg that the datasource gets
is only config that is present in /etc/cloud/cloud.cfg.d and /etc/cloud.cfg
the user's provided cloud-config is not yet present (it has not yet been read).

I think that can be made acceptable though, see comment inline.


Diff comments:

> diff --git a/cloudinit/sources/DataSourceGCE.py b/cloudinit/sources/DataSourceGCE.py
> index ad6dae3..c1fa354 100644
> --- a/cloudinit/sources/DataSourceGCE.py
> +++ b/cloudinit/sources/DataSourceGCE.py
> @@ -92,15 +97,59 @@ class DataSourceGCE(sources.DataSource):
>          return self.availability_zone.rsplit('-', 1)[0]
>  
>  
> -def _trim_key(public_key):
> -    # GCE takes sshKeys attribute in the format of '<user>:<public_key>'
> -    # so we have to trim each key to remove the username part
> +def _has_expired(public_key):
> +    # Check whether an SSH key is expired. Public key input is a single SSH
> +    # public key in the GCE specific key format documented here:
> +    # https://cloud.google.com/compute/docs/instances/adding-removing-ssh-keys#sshkeyformat
> +    try:
> +        # Check for the Google-specific schema identifier.
> +        schema, json_str = public_key.split(None, 3)[2:]
> +    except (ValueError, AttributeError):
> +        return False
> +
> +    # Do not expire keys if they do not have the expected schema identifier.
> +    if schema != 'google-ssh':
> +        return False
> +
> +    try:
> +        json_obj = json.loads(json_str)
> +    except ValueError:
> +        return False
> +
> +    # Do not expire keys if there is no expriation timestamp.
> +    if 'expireOn' not in json_obj:
> +        return False
> +
> +    expire_str = json_obj['expireOn']
> +    format_str = '%Y-%m-%dT%H:%M:%S+0000'
>      try:
> -        index = public_key.index(':')
> -        if index > 0:
> -            return public_key[(index + 1):]
> -    except Exception:
> -        return public_key
> +        expire_time = datetime.datetime.strptime(expire_str, format_str)
> +    except ValueError:
> +        return False
> +
> +    # Expire the key if and only if we have exceeded the expiration timestamp.
> +    return datetime.datetime.utcnow() > expire_time
> +
> +
> +def _parse_public_keys(public_keys_data):
> +    # Parse the SSH key data for the Ubuntu user account. Public keys input is
> +    # a newline separated string containing SSH public keys in the GCE specific
> +    # key format documented here:
> +    # https://cloud.google.com/compute/docs/instances/adding-removing-ssh-keys#sshkeyformat
> +    public_keys = []
> +    if not public_keys_data:
> +        return public_keys
> +    lines = [line for line in public_keys_data.splitlines() if line]
> +    for line in lines:
> +        if not all(ord(c) < 128 for c in line):
> +            continue
> +        split_line = line.split(':', 1)
> +        if len(split_line) != 2:
> +            continue
> +        user, key = split_line
> +        if user == 'ubuntu' and not _has_expired(key):

maybe 'default' or default_user as described above would be sufficient here.

Then if i added a key for user 'default', it'd get into the public keys
and further into the 'ubuntu' user (or whatever user these should go to).

And 'ubuntu' would also get in there on Ubuntu and 'centos' on centos.

If the user wanted to change what the default user was in user-data, then they'd have to populate keys with 'default' as the name to make it stick.

> +            public_keys.append(key)
> +    return public_keys
>  
>  
>  def read_md(address=None, platform_check=True):
> @@ -149,17 +195,25 @@ def read_md(address=None, platform_check=True):
>              return ret
>          md[mkey] = value
>  
> -    if md['public-keys']:
> -        lines = md['public-keys'].splitlines()
> -        md['public-keys'] = [_trim_key(k) for k in lines]
> +    print('Instance: %s' % md['instance-data'])
> +    print('Instance Type: %s' % type(md['instance-data']))

drop prints

> +    instance_data = json.loads(md['instance-data'] or '{}')
> +    project_data = json.loads(md['project-data'] or '{}')
> +    valid_keys = [instance_data.get('sshKeys'), instance_data.get('ssh-keys')]
> +    block_project = instance_data.get('block-project-ssh-keys', '').lower()
> +    if block_project != 'true' and not instance_data.get('sshKeys'):
> +        valid_keys.append(project_data.get('ssh-keys'))
> +        valid_keys.append(project_data.get('sshKeys'))
> +    public_keys_data = '\n'.join([key for key in valid_keys if key])
> +    md['public-keys'] = _parse_public_keys(public_keys_data)
>  
>      if md['availability-zone']:
>          md['availability-zone'] = md['availability-zone'].split('/')[-1]
>  
> -    encoding = md.get('user-data-encoding')
> +    encoding = instance_data.get('user-data-encoding')
>      if encoding:
>          if encoding == 'base64':
> -            md['user-data'] = b64decode(md['user-data'])
> +            md['user-data'] = b64decode(instance_data.get('user-data'))
>          else:
>              LOG.warning('unknown user-data-encoding: %s, ignoring', encoding)
>  


-- 
https://code.launchpad.net/~illfelder/cloud-init/+git/cloud-init/+merge/334777
Your team cloud-init commiters is requested to review the proposed merge of ~illfelder/cloud-init:master into cloud-init:master.


References