Пример #1
0
def passthrough(url=''):
    log.debug('Did not match credentials request url; passing through.')
    req = requests.get('{0}/{1}'.format(app.config['METADATA_URL'], url),
                       stream=True)
    return Response(stream_with_context(req.iter_content()),
                    content_type=req.headers['content-type'],
                    status=req.status_code)
Пример #2
0
def check_role_name_from_ip(ip, requested_role):
    role_name = get_role_name_from_ip(ip)
    if role_name == requested_role:
        log.debug('Detected Role: {0}, Requested Role: {1}'.format(
            role_name, requested_role))
        return True
    return False
Пример #3
0
def get_iam_info(api_version, junk=None):
    role_params_from_ip = roles.get_role_params_from_ip(request.remote_addr)
    if role_params_from_ip['name']:
        log.debug('Providing IAM role info for {0}'.format(role_params_from_ip['name']))
        return jsonify(roles.get_role_info_from_params(role_params_from_ip))
    else:
        log.error('Role name not found; returning 404.')
        return '', 404
Пример #4
0
def get_iam_info(api_version, junk=None):
    role_name_from_ip = roles.get_role_name_from_ip(request.remote_addr)
    if role_name_from_ip:
        log.debug('Providing IAM role info for {0}'.format(role_name_from_ip))
        return jsonify(roles.get_role_info_from_ip(request.remote_addr))
    else:
        log.error('Role name not found; returning 404.')
        return '', 404
Пример #5
0
def find_container(ip):
    pattern = re.compile(app.config['HOSTNAME_MATCH_REGEX'])
    client = docker_client()
    # Try looking at the container mapping cache first
    if ip in CONTAINER_MAPPING:
        log.info('Container id for IP {0} in cache'.format(ip))
        try:
            with PrintingBlockTimer('Container inspect'):
                container = client.inspect_container(CONTAINER_MAPPING[ip])
            return container
        except docker.errors.NotFound:
            msg = 'Container id {0} no longer mapped to {1}'
            log.error(msg.format(CONTAINER_MAPPING[ip], ip))
            del CONTAINER_MAPPING[ip]

    _fqdn = None
    with PrintingBlockTimer('Reverse DNS'):
        if app.config['ROLE_REVERSE_LOOKUP']:
            try:
                _fqdn = socket.gethostbyaddr(ip)[0]
            except socket.error as e:
                log.error('gethostbyaddr failed: {0}'.format(e.args))
                pass

    with PrintingBlockTimer('Container fetch'):
        _ids = [c['Id'] for c in client.containers()]

    for _id in _ids:
        try:
            with PrintingBlockTimer('Container inspect'):
                c = client.inspect_container(_id)
        except docker.errors.NotFound:
            log.error('Container id {0} not found'.format(_id))
            continue
        # Try matching container to caller by IP address
        _ip = c['NetworkSettings']['IPAddress']
        if ip == _ip:
            msg = 'Container id {0} mapped to {1} by IP match'
            log.debug(msg.format(_id, ip))
            CONTAINER_MAPPING[ip] = _id
            return c
        # Try matching container to caller by hostname match
        if app.config['ROLE_REVERSE_LOOKUP']:
            hostname = c['Config']['Hostname']
            domain = c['Config']['Domainname']
            fqdn = '{0}.{1}'.format(hostname, domain)
            # Default pattern matches _fqdn == fqdn
            _groups = re.match(pattern, _fqdn).groups()
            groups = re.match(pattern, fqdn).groups()
            if _groups and groups:
                if groups[0] == _groups[0]:
                    msg = 'Container id {0} mapped to {1} by FQDN match'
                    log.debug(msg.format(_id, ip))
                    CONTAINER_MAPPING[ip] = _id
                    return c

    log.error('No container found for ip {0}'.format(ip))
    return None
Пример #6
0
def passthrough(url=''):
    log.debug('Did not match credentials request url; passing through.')
    req = requests.get(
        '{0}/{1}'.format(app.config['METADATA_URL'], url),
        stream=True
    )
    return Response(
        stream_with_context(req.iter_content()),
        content_type=req.headers['content-type']
    )
Пример #7
0
def iam_role_info(api_version, junk=None):
    if not _supports_iam(api_version):
        return passthrough(request.path)

    role_name_from_ip = roles.get_role_name_from_ip(request.remote_addr)
    if role_name_from_ip:
        log.debug('Providing IAM role info for {0}'.format(role_name_from_ip))
        return jsonify(roles.get_role_info_from_ip(request.remote_addr))
    else:
        log.error('Role name not found; returning 404.')
        return '', 404
Пример #8
0
def iam_role_info(api_version, junk=None):
    if not _supports_iam(api_version):
        return passthrough(request.path)

    role_params_from_ip = roles.get_role_params_from_ip(request.remote_addr)
    if role_params_from_ip['name']:
        log.debug('Providing IAM role info for {0}'.format(
            role_params_from_ip['name']))
        return jsonify(roles.get_role_info_from_params(role_params_from_ip))
    else:
        log.error('Role name not found; returning 404.')
        return '', 404
Пример #9
0
def iam_sts_credentials(api_version, requested_role, junk=None):
    if not _supports_iam(api_version):
        return passthrough(request.path)

    if not roles.check_role_name_from_ip(request.remote_addr, requested_role):
        msg = "Role name {0} doesn't match expected role for container"
        log.error(msg.format(requested_role))
        return '', 404
    role_name = roles.get_role_name_from_ip(request.remote_addr,
                                            stripped=False)
    log.debug('Providing assumed role credentials for {0}'.format(role_name))
    assumed_role = roles.get_assumed_role_credentials(requested_role=role_name,
                                                      api_version=api_version)
    return jsonify(assumed_role)
Пример #10
0
def iam_sts_credentials(api_version, requested_role, junk=None):
    if not _supports_iam(api_version):
        return passthrough(request.path)

    try:
        role_params = roles.get_role_params_from_ip(
            request.remote_addr, requested_role=requested_role)
    except roles.UnexpectedRoleError:
        msg = "Role name {0} doesn't match expected role for container"
        log.error(msg.format(requested_role))
        return '', 404

    log.debug('Providing assumed role credentials for {0}'.format(
        role_params['name']))
    assumed_role = roles.get_assumed_role_credentials(role_params=role_params,
                                                      api_version=api_version)
    return jsonify(assumed_role)
Пример #11
0
def iam_sts_credentials(api_version, requested_role, junk=None):
    if not _supports_iam(api_version):
        return passthrough(request.path)

    if not roles.check_role_name_from_ip(request.remote_addr, requested_role):
        msg = "Role name {0} doesn't match expected role for container"
        log.error(msg.format(requested_role))
        return '', 404
    role_name = roles.get_role_name_from_ip(
        request.remote_addr,
        stripped=False
    )
    log.debug('Providing assumed role credentials for {0}'.format(role_name))
    assumed_role = roles.get_assumed_role_credentials(
        requested_role=role_name,
        api_version=api_version
    )
    return jsonify(assumed_role)
Пример #12
0
def iam_sts_credentials(api_version, requested_role, junk=None):
    if not _supports_iam(api_version):
        return passthrough(request.path)

    try:
        role_params = roles.get_role_params_from_ip(
            request.remote_addr,
            requested_role=requested_role
        )
    except roles.UnexpectedRoleError:
        msg = "Role name {0} doesn't match expected role for container"
        log.error(msg.format(requested_role))
        return '', 404

    log.debug('Providing assumed role credentials for {0}'.format(role_params['name']))
    assumed_role = roles.get_assumed_role_credentials(
        role_params=role_params,
        api_version=api_version
    )
    return jsonify(assumed_role)
Пример #13
0
def get_role_name_from_ip(ip, stripped=True):
    if app.config['ROLE_MAPPING_FILE']:
        return ROLE_MAPPINGS.get(ip, app.config['DEFAULT_ROLE'])
    container = find_container(ip)
    if container:
        env = container['Config']['Env']
        for e in env:
            key, val = e.split('=', 1)
            if key == 'IAM_ROLE':
                if stripped:
                    return val.split('@')[0]
                else:
                    return val
        msg = "Couldn't find IAM_ROLE variable. Returning DEFAULT_ROLE: {0}"
        log.debug(msg.format(app.config['DEFAULT_ROLE']))
        if stripped:
            return app.config['DEFAULT_ROLE'].split('@')[0]
        else:
            return app.config['DEFAULT_ROLE']
    else:
        return None
Пример #14
0
def get_role_name_from_ip(ip, stripped=True):
    if app.config['ROLE_MAPPING_FILE']:
        return ROLE_MAPPINGS.get(ip, app.config['DEFAULT_ROLE'])
    container = find_container(ip)
    if container:
        env = container['Config']['Env']
        for e in env:
            key, val = e.split('=', 1)
            if key == 'IAM_ROLE':
                if stripped:
                    return val.split('@')[0]
                else:
                    return val
        msg = "Couldn't find IAM_ROLE variable. Returning DEFAULT_ROLE: {0}"
        log.debug(msg.format(app.config['DEFAULT_ROLE']))
        if stripped:
            return app.config['DEFAULT_ROLE'].split('@')[0]
        else:
            return app.config['DEFAULT_ROLE']
    else:
        return None
Пример #15
0
def get_role_params_from_ip(ip, requested_role=None):
    params = {
        'name': None,
        'account_id': None,
        'external_id': None,
        'session_name': None
    }
    role_name = None
    if app.config['ROLE_MAPPING_FILE']:
        role = ROLE_MAPPINGS.get(ip, app.config['DEFAULT_ROLE'])
        if isinstance(role, dict):
            params.update(role)
        else:
            role_name = role
    else:
        container = find_container(ip)
        if container:
            env = container['Config']['Env'] or []
            # Look up IAM_ROLE and IAM_EXTERNAL_ID values from environment
            for e in env:
                key, val = e.split('=', 1)
                if key == 'IAM_ROLE':
                    if val.startswith('arn:aws'):
                        m = RE_IAM_ARN.match(val)
                        val = '{0}@{1}'.format(m.group(2), m.group(1))
                    role_name = val
                elif key == 'IAM_EXTERNAL_ID':
                    params['external_id'] = val
            if not role_name:
                msg = "Couldn't find IAM_ROLE variable. Returning DEFAULT_ROLE: {0}"
                log.debug(msg.format(app.config['DEFAULT_ROLE']))
                role_name = app.config['DEFAULT_ROLE']

            # Optionally, look up role session name from environment or labels
            if app.config['ROLE_SESSION_KEY']:
                skey = app.config['ROLE_SESSION_KEY']
                sval = None
                if skey.startswith('Env:'):
                    skey = skey[4:]
                    for e in env:
                        key, val = e.split('=', 1)
                        if skey == key:
                            sval = val
                elif skey.startswith('Labels:'):
                    skey = skey[7:]
                    if container['Config']['Labels'] and skey in container[
                            'Config']['Labels']:
                        sval = container['Config']['Labels'][skey]
                if sval and len(sval) > 1:
                    # The docs on RoleSessionName are slightly contradictory, and state:
                    # > The regex used to validate this parameter is a string of characters consisting
                    # > of upper- and lower-case alphanumeric characters with no spaces. You can also
                    # > include underscores or any of the following characters: =,.@-
                    # > Type: String
                    # > Length Constraints: Minimum length of 2. Maximum length of 64.
                    # > Pattern: [\w+=,.@-]*
                    # We replace any invalid chars with underscore, and trim to 64.
                    params['session_name'] = re.sub(r'[^\w+=,.@-]', '_',
                                                    sval)[:64]
    if role_name:
        role_parts = role_name.split('@')
        params['name'] = role_parts[0]
        if len(role_parts) > 1:
            params['account_id'] = role_parts[1]

    if requested_role and requested_role != params['name']:
        raise UnexpectedRoleError

    return params
Пример #16
0
def find_container(ip):
    pattern = re.compile(app.config['HOSTNAME_MATCH_REGEX'])
    client = docker_client()
    # Try looking at the container mapping cache first
    if ip in CONTAINER_MAPPING:
        log.info('Container id for IP {0} in cache'.format(ip))
        try:
            with PrintingBlockTimer('Container inspect'):
                container = client.inspect_container(CONTAINER_MAPPING[ip])
            # Only return a cached container if it is running.
            if container['State']['Running']:
                return container
            else:
                log.error('Container id {0} is no longger running'.format(ip))
                del CONTAINER_MAPPING[ip]
        except docker.errors.NotFound:
            msg = 'Container id {0} no longer mapped to {1}'
            log.error(msg.format(CONTAINER_MAPPING[ip], ip))
            del CONTAINER_MAPPING[ip]

    _fqdn = None
    with PrintingBlockTimer('Reverse DNS'):
        if app.config['ROLE_REVERSE_LOOKUP']:
            try:
                _fqdn = socket.gethostbyaddr(ip)[0]
            except socket.error as e:
                log.error('gethostbyaddr failed: {0}'.format(e.args))
                pass

    with PrintingBlockTimer('Container fetch'):
        _ids = [c['Id'] for c in client.containers()]

    for _id in _ids:
        try:
            with PrintingBlockTimer('Container inspect'):
                c = client.inspect_container(_id)
        except docker.errors.NotFound:
            log.error('Container id {0} not found'.format(_id))
            continue
        # Try matching container to caller by IP address
        _ip = c['NetworkSettings']['IPAddress']
        if ip == _ip:
            msg = 'Container id {0} mapped to {1} by IP match'
            log.debug(msg.format(_id, ip))
            CONTAINER_MAPPING[ip] = _id
            return c
        # Try matching container to caller by hostname match
        if app.config['ROLE_REVERSE_LOOKUP']:
            hostname = c['Config']['Hostname']
            domain = c['Config']['Domainname']
            fqdn = '{0}.{1}'.format(hostname, domain)
            # Default pattern matches _fqdn == fqdn
            _groups = re.match(pattern, _fqdn).groups()
            groups = re.match(pattern, fqdn).groups()
            if _groups and groups:
                if groups[0] == _groups[0]:
                    msg = 'Container id {0} mapped to {1} by FQDN match'
                    log.debug(msg.format(_id, ip))
                    CONTAINER_MAPPING[ip] = _id
                    return c

    log.error('No container found for ip {0}'.format(ip))
    return None
Пример #17
0
def block_user_data(api_version):
    log.debug('Blocking request for user-data.')
    return 'ACCESS FORBIDDEN', 403
Пример #18
0
def find_container(ip):
    pattern = re.compile(app.config['HOSTNAME_MATCH_REGEX'])
    client = docker_client()
    # Try looking at the container mapping cache first
    container_id = CONTAINER_MAPPING.get(ip)
    if container_id:
        log.info('Container id for IP {0} in cache'.format(ip))
        try:
            with PrintingBlockTimer('Container inspect'):
                container = client.inspect_container(container_id)
            # Only return a cached container if it is running.
            if container['State']['Running']:
                return container
            else:
                log.error('Container id {0} is no longer running'.format(ip))
                if ip in CONTAINER_MAPPING:
                    del CONTAINER_MAPPING[ip]
        except docker.errors.NotFound:
            msg = 'Container id {0} no longer mapped to {1}'
            log.error(msg.format(container_id, ip))
            if ip in CONTAINER_MAPPING:
                del CONTAINER_MAPPING[ip]

    _fqdn = None
    with PrintingBlockTimer('Reverse DNS'):
        if app.config['ROLE_REVERSE_LOOKUP']:
            try:
                _fqdn = socket.gethostbyaddr(ip)[0]
            except socket.error as e:
                log.error('gethostbyaddr failed: {0}'.format(e.args))
                pass

    with PrintingBlockTimer('Container fetch'):
        _ids = [c['Id'] for c in client.containers()]

    for _id in _ids:
        try:
            with PrintingBlockTimer('Container inspect'):
                c = client.inspect_container(_id)
        except docker.errors.NotFound:
            log.error('Container id {0} not found'.format(_id))
            continue
        # Try matching container to caller by IP address
        _ip = c['NetworkSettings']['IPAddress']
        if ip == _ip:
            msg = 'Container id {0} mapped to {1} by IP match'
            log.debug(msg.format(_id, ip))
            CONTAINER_MAPPING[ip] = _id
            return c
        # Try matching container to caller by sub network IP address
        _networks = c['NetworkSettings']['Networks']
        if _networks:
            for _network in _networks:
                if _networks[_network]['IPAddress'] == ip:
                    msg = 'Container id {0} mapped to {1} by sub-network IP match'
                    log.debug(msg.format(_id, ip))
                    CONTAINER_MAPPING[ip] = _id
                    return c
        # Not Found ? Let's see if we are running under rancher 1.2+,which uses a label to store the IP
        try:
            _labels = c.get('Config', {}).get('Labels', {})
        except (KeyError, ValueError):
            _labels = {}
        try:
            if _labels.get('io.rancher.container.ip'):
                _ip = _labels.get('io.rancher.container.ip').split("/")[0]
        except docker.errors.NotFound:
            log.error('Container: {0} Label container.ip not found'.format(_id))
        if ip == _ip:
            msg = 'Container id {0} mapped to {1} by Rancher IP match'
            log.debug(msg.format(_id, ip))
            CONTAINER_MAPPING[ip] = _id
            return c
        # Try matching container to caller by hostname match
        if app.config['ROLE_REVERSE_LOOKUP']:
            hostname = c['Config']['Hostname']
            domain = c['Config']['Domainname']
            fqdn = '{0}.{1}'.format(hostname, domain)
            # Default pattern matches _fqdn == fqdn
            _groups = re.match(pattern, _fqdn).groups()
            groups = re.match(pattern, fqdn).groups()
            if _groups and groups:
                if groups[0] == _groups[0]:
                    msg = 'Container id {0} mapped to {1} by FQDN match'
                    log.debug(msg.format(_id, ip))
                    CONTAINER_MAPPING[ip] = _id
                    return c

    log.error('No container found for ip {0}'.format(ip))
    return None
Пример #19
0
 def __exit__(self, *args):
     super(PrintingBlockTimer, self).__exit__(*args)
     msg = "Execution took {0:f}s".format(self.exec_duration)
     if self.prefix:
         msg = self.prefix + ': ' + msg
     log.debug(msg)
Пример #20
0
def get_role_params_from_ip(ip, requested_role=None):
    params = {'name': None, 'account_id': None, 'external_id': None, 'session_name': None}
    role_name = None
    if app.config['ROLE_MAPPING_FILE']:
        role = ROLE_MAPPINGS.get(ip, app.config['DEFAULT_ROLE'])
        if isinstance(role, dict):
            params.update(role)
        else:
            role_name = role
    else:
        container = find_container(ip)
        if container:
            env = container['Config']['Env'] or []
            # Look up IAM_ROLE and IAM_EXTERNAL_ID values from environment
            for e in env:
                key, val = e.split('=', 1)
                if key == 'IAM_ROLE':
                    if val.startswith('arn:aws'):
                        m = RE_IAM_ARN.match(val)
                        val = '{0}@{1}'.format(m.group(2), m.group(1))
                    role_name = val
                elif key == 'IAM_EXTERNAL_ID':
                    params['external_id'] = val
            if not role_name:
                msg = "Couldn't find IAM_ROLE variable. Returning DEFAULT_ROLE: {0}"
                log.debug(msg.format(app.config['DEFAULT_ROLE']))
                role_name = app.config['DEFAULT_ROLE']

            # Optionally, look up role session name from environment or labels
            if app.config['ROLE_SESSION_KEY']:
                skey = app.config['ROLE_SESSION_KEY']
                sval = None
                if skey.startswith('Env:'):
                    skey = skey[4:]
                    for e in env:
                        key, val = e.split('=', 1)
                        if skey == key:
                            sval = val
                elif skey.startswith('Labels:'):
                    skey = skey[7:]
                    if container['Config']['Labels'] and skey in container['Config']['Labels']:
                        sval = container['Config']['Labels'][skey]
                if sval and len(sval) > 1:
                    # The docs on RoleSessionName are slightly contradictory, and state:
                    # > The regex used to validate this parameter is a string of characters consisting
                    # > of upper- and lower-case alphanumeric characters with no spaces. You can also
                    # > include underscores or any of the following characters: =,.@-
                    # > Type: String
                    # > Length Constraints: Minimum length of 2. Maximum length of 64.
                    # > Pattern: [\w+=,.@-]*
                    # We replace any invalid chars with underscore, and trim to 64.
                    params['session_name'] = re.sub(r'[^\w+=,.@-]', '_', sval)[:64]
    if role_name:
        role_parts = role_name.split('@')
        params['name'] = role_parts[0]
        if len(role_parts) > 1:
            params['account_id'] = role_parts[1]

    if requested_role and requested_role != params['name']:
        raise UnexpectedRoleError

    return params
Пример #21
0
 def __exit__(self, *args):
     super(PrintingBlockTimer, self).__exit__(*args)
     msg = "Execution took {0:f}s".format(self.exec_duration)
     if self.prefix:
         msg = self.prefix + ': ' + msg
     log.debug(msg)
Пример #22
0
def find_container(ip):
    pattern = re.compile(app.config['HOSTNAME_MATCH_REGEX'])
    client = docker_client()
    # Try looking at the container mapping cache first
    if ip in CONTAINER_MAPPING:
        log.info('Container id for IP {0} in cache'.format(ip))
        try:
            with PrintingBlockTimer('Container inspect'):
                container = client.inspect_container(CONTAINER_MAPPING[ip])
            # Only return a cached container if it is running.
            if container['State']['Running']:
                return container
            else:
                log.error('Container id {0} is no longer running'.format(ip))
                del CONTAINER_MAPPING[ip]
        except docker.errors.NotFound:
            msg = 'Container id {0} no longer mapped to {1}'
            log.error(msg.format(CONTAINER_MAPPING[ip], ip))
            del CONTAINER_MAPPING[ip]

    _fqdn = None
    with PrintingBlockTimer('Reverse DNS'):
        if app.config['ROLE_REVERSE_LOOKUP']:
            try:
                _fqdn = socket.gethostbyaddr(ip)[0]
            except socket.error as e:
                log.error('gethostbyaddr failed: {0}'.format(e.args))
                pass

    with PrintingBlockTimer('Container fetch'):
        _ids = [c['Id'] for c in client.containers()]

    for _id in _ids:
        try:
            with PrintingBlockTimer('Container inspect'):
                c = client.inspect_container(_id)
        except docker.errors.NotFound:
            log.error('Container id {0} not found'.format(_id))
            continue
        # Try matching container to caller by IP address
        _ip = c['NetworkSettings']['IPAddress']
        if ip == _ip:
            msg = 'Container id {0} mapped to {1} by IP match'
            log.debug(msg.format(_id, ip))
            CONTAINER_MAPPING[ip] = _id
            return c
        # Try matching container to caller by sub network IP address
        _networks = c['NetworkSettings']['Networks']
        if _networks:
            for _network in _networks:
                if _networks[_network]['IPAddress'] == ip:
                    msg = 'Container id {0} mapped to {1} by sub-network IP match'
                    log.debug(msg.format(_id, ip))
                    CONTAINER_MAPPING[ip] = _id
                    return c
        # Not Found ? Let's see if we are running under rancher 1.2+,which uses a label to store the IP
        try:
            _labels = c.get('Config', {}).get('Labels', {})
        except (KeyError, ValueError):
            _labels = {}
        try:
            if _labels.get('io.rancher.container.ip'):
                _ip = _labels.get('io.rancher.container.ip').split("/")[0]
        except docker.errors.NotFound:
            log.error(
                'Container: {0} Label container.ip not found'.format(_id))
        if ip == _ip:
            msg = 'Container id {0} mapped to {1} by Rancher IP match'
            log.debug(msg.format(_id, ip))
            CONTAINER_MAPPING[ip] = _id
            return c
        # Try matching container to caller by hostname match
        if app.config['ROLE_REVERSE_LOOKUP']:
            hostname = c['Config']['Hostname']
            domain = c['Config']['Domainname']
            fqdn = '{0}.{1}'.format(hostname, domain)
            # Default pattern matches _fqdn == fqdn
            _groups = re.match(pattern, _fqdn).groups()
            groups = re.match(pattern, fqdn).groups()
            if _groups and groups:
                if groups[0] == _groups[0]:
                    msg = 'Container id {0} mapped to {1} by FQDN match'
                    log.debug(msg.format(_id, ip))
                    CONTAINER_MAPPING[ip] = _id
                    return c

    log.error('No container found for ip {0}'.format(ip))
    return None
Пример #23
0
def get_role_params_from_ip(ip, requested_role=None):
    params = {
        'name': None,
        'account_id': None,
        'external_id': None,
        'session_name': None
    }
    role_name = None
    if app.config['ROLE_MAPPING_FILE']:
        role = ROLE_MAPPINGS.get(ip, app.config['DEFAULT_ROLE'])
        if isinstance(role, dict):
            params.update(role)
        else:
            role_name = role
    else:
        container = find_container(ip)
        if container:
            env = container['Config']['Env'] or []
            # Look up IAM_ROLE and IAM_EXTERNAL_ID values from environment
            aws_id = chain_ns = chain_role = proposer_number = voter_number = alloc_index = aws_subnet = None
            for e in env:
                key, val = split_envvar(e)
                if key == 'IAM_ROLE':
                    m = RE_IAM_ARN.match(val)
                    if m:
                        val = '{0}@{1}'.format(m.group(2), m.group(1))
                    role_name = val
                elif key == 'IAM_EXTERNAL_ID':
                    params['external_id'] = val
                elif key == 'NOMAD_META_AWS_ACCOUNT_ID':
                    aws_id = val
                elif key == 'NOMAD_META_CHAIN_NS':
                    chain_ns = val
                elif key == 'NOMAD_META_CHAIN_ROLE':
                    chain_role = val
                elif key == 'NOMAD_META_PORPOSER_NUMBER':
                    proposer_number = val
                elif key == 'NOMAD_META_VOTER_NUMBER':
                    voter_number = val
                elif key == 'NOMAD_ALLOC_INDEX':
                    alloc_index = val
                elif key == 'NOMAD_META_AWS_SUBNET':
                    aws_subnet = val
            start_number = 0
            if chain_role == 'proposer':
                data = ast.literal_eval(proposer_number)
                for key in sorted(data.keys()):
                    if key != aws_subnet:
                        start_number += int(data.get(key))
                    else:
                        break
                chain_role = "accelerator"
            elif chain_role == 'voter':
                data = ast.literal_eval(voter_number)
                for key in sorted(data.keys()):
                    if key != aws_subnet:
                        start_number += int(data.get(key))
                    else:
                        break
                chain_role = "consensus"
            if chain_ns and chain_role and alloc_index and aws_subnet:
                r_number = start_number + int(alloc_index)
                r_number = "%03d" % r_number
                role_name = '{0}-{1}-{2}@{3}'.format(chain_ns, chain_role,
                                                     r_number, aws_id)
            if not role_name:
                msg = "Couldn't find IAM_ROLE variable. Returning DEFAULT_ROLE: {0}"
                log.debug(msg.format(app.config['DEFAULT_ROLE']))
                role_name = app.config['DEFAULT_ROLE']
            # Optionally, look up role session name from environment or labels
            if app.config['ROLE_SESSION_KEY']:
                skey = app.config['ROLE_SESSION_KEY']
                sval = None
                if skey.startswith('Env:'):
                    skey = skey[4:]
                    for e in env:
                        key, val = split_envvar(e)
                        if skey == key:
                            sval = val
                elif skey.startswith('Labels:'):
                    skey = skey[7:]
                    if container['Config']['Labels'] and skey in container[
                            'Config']['Labels']:
                        sval = container['Config']['Labels'][skey]
                if sval and len(sval) > 1:
                    # The docs on RoleSessionName are slightly contradictory, and state:
                    # > The regex used to validate this parameter is a string of characters consisting
                    # > of upper- and lower-case alphanumeric characters with no spaces. You can also
                    # > include underscores or any of the following characters: =,.@-
                    # > Type: String
                    # > Length Constraints: Minimum length of 2. Maximum length of 64.
                    # > Pattern: [\w+=,.@-]*
                    # We replace any invalid chars with underscore, and trim to 64.
                    params['session_name'] = re.sub(r'[^\w+=,.@-]', '_',
                                                    sval)[:64]
    if role_name:
        role_parts = role_name.split('@')
        params['name'] = role_parts[0]
        if len(role_parts) > 1:
            params['account_id'] = role_parts[1]

    if requested_role and requested_role != params['name']:
        raise UnexpectedRoleError

    return params