You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在Lambda中获取超1小时临时凭证并规避角色链问题(SAML错误)

问题描述

在Lambda中通过编程方式对用户做身份验证,调用AssumeRoleWithSAML API获取凭证,之后用该凭证扮演另一个角色,生成有效期超过1小时且无角色链问题的临时凭证。不想创建IAM用户,希望用联合用户凭证实现,但代码运行报错,请求帮助。

import requests
import boto3
import base64

def authenticate_with_okta(username, password, okta_org_url, okta_app_url):
    okta_authn_url = f"{okta_org_url}/api/v1/authn"

    # Send a POST request to the Okta Authn endpoint to authenticate the user
    response = requests.post(okta_authn_url, json={
        "username": username,
        "password": password
    })
    print(response)
    if response.status_code == 200:
        # Extract the SAML assertion from the response JSON
        auth_response = response.json()
        saml_assertion = auth_response.get('sessionToken')
        if saml_assertion:
            return saml_assertion
    else:
        print(f"Authentication failed. Status code: {response.status_code}")
    return None

def decode_saml_assertion(saml_assertion):
    try:
        decoded_saml = base64.b64decode(saml_assertion)
        return decoded_saml
    except Exception as e:
        print(f"Error decoding SAML Assertion: {e}")
        return None

# Decode and print the SAML Assertion
decoded_saml_assertion = decode_saml_assertion
print(decoded_saml_assertion)

def assume_role_with_saml(saml_assertion, role_arn, principal_arn, region_name='us-east-1'):
    print("Received SAML Assertion:")
    print(saml_assertion)

    client = boto3.client('sts', region_name=region_name)
    response = client.assume_role_with_saml(
        RoleArn=role_arn,
        PrincipalArn=principal_arn,
        SAMLAssertion=saml_assertion
    )

    print("STS Response:")
    print(response)

    return response['Credentials']

def main():
    # Replace with your Okta credentials and configuration
    okta_username = "MyOktaUser@lab.com"
    okta_password = "MyComplexPassword"
    okta_org_url = "https://mydomain.okta.com"  # Replace with your Okta domain URL
    okta_app_url = "https://mydomain/home/amazon_appstream/0oa8alauh3v3ise4C5d7/aln1al3ek55Es08M81d8"     # Replace with your Okta app URL

    # Replace with your AWS role ARN and principal ARN
    aws_role_arn = "arn:aws:iam::1234567890:role/Test_Role"
    aws_principal_arn = "arn:aws:iam::1234567890:saml-provider/Okta"

    # Step 1: Authenticate with Okta and get SAML Assertion
    saml_assertion = authenticate_with_okta(okta_username, okta_password, okta_org_url, okta_app_url)
    if not saml_assertion:
        print("Failed to obtain SAML Assertion.")
        return

    # Step 2: Use SAML Assertion to Assume AWS Role and get temporary credentials
    try:
        credentials = assume_role_with_saml(saml_assertion, aws_role_arn, aws_principal_arn)
        print("Temporary credentials fetched successfully!")
        print("Access Key ID:", credentials['AccessKeyId'])
        print("Secret Access Key:", credentials['SecretAccessKey'])
        print("Session Token:", credentials['SessionToken'])
    except Exception as e:
        print("Error assuming AWS role:", e)

if __name__ == "__main__":
    main()

错误信息

Received SAML Assertion:
20111Fw2lcP1_zs-PI6z_9dF5A_-TcIbDwv-5zWaVsg4GP6SiUA_9s0
Error assuming AWS role: An error occurred (InvalidIdentityToken) when calling the AssumeRoleWithSAML operation: Invalid base64 SAMLResponse (Service: AWSOpenIdDiscoveryService; Status Code: 400; Error Code: AuthSamlInvalidSamlResponseException; Request ID: 80a016bb-17ca-4162-bf68-08f63eba32d2; Proxy: null)

问题根源与修复方案

问题根源

你把Okta身份验证返回的sessionToken当成了SAML断言传给AWS,这是核心错误。sessionToken只是用户会话令牌,不是符合AWS要求的SAML断言,所以触发了无效令牌报错。

修复后的完整代码

import requests
import boto3
from bs4 import BeautifulSoup

def authenticate_with_okta(username, password, okta_org_url, okta_app_url):
    okta_authn_url = f"{okta_org_url}/api/v1/authn"

    # 1. 用户身份验证获取sessionToken
    response = requests.post(okta_authn_url, json={
        "username": username,
        "password": password
    })
    if response.status_code != 200:
        print(f"身份验证失败,状态码: {response.status_code}")
        return None
    
    auth_response = response.json()
    session_token = auth_response.get('sessionToken')
    if not session_token:
        print("未获取到sessionToken")
        return None

    # 2. 用sessionToken访问Okta应用,提取SAML断言
    app_response = requests.get(okta_app_url, params={'sessionToken': session_token})
    if app_response.status_code != 200:
        print(f"访问Okta应用失败,状态码: {app_response.status_code}")
        return None
    
    # 解析HTML页面获取SAMLResponse
    soup = BeautifulSoup(app_response.content, 'html.parser')
    saml_input = soup.find('input', {'name': 'SAMLResponse'})
    if not saml_input:
        print("页面中未找到SAMLResponse")
        return None
    
    return saml_input['value']

def assume_role_with_saml(saml_assertion, role_arn, principal_arn, region_name='us-east-1'):
    client = boto3.client('sts', region_name=region_name)
    response = client.assume_role_with_saml(
        RoleArn=role_arn,
        PrincipalArn=principal_arn,
        SAMLAssertion=saml_assertion,
        DurationSeconds=3600  # 可设置最长1小时,如需更长需后续调用AssumeRole
    )
    return response['Credentials']

def assume_another_role(base_credentials, target_role_arn, region_name='us-east-1'):
    # 用SAML获取的凭证扮演另一个角色,最长可设置12小时有效期
    sts_client = boto3.client(
        'sts',
        region_name=region_name,
        aws_access_key_id=base_credentials['AccessKeyId'],
        aws_secret_access_key=base_credentials['SecretAccessKey'],
        aws_session_token=base_credentials['SessionToken']
    )
    response = sts_client.assume_role(
        RoleArn=target_role_arn,
        RoleSessionName="saml-federated-session",
        DurationSeconds=43200  # 最长12小时,需目标角色信任策略允许
    )
    return response['Credentials']

def main():
    # 替换为你的配置信息
    okta_username = "MyOktaUser@lab.com"
    okta_password = "MyComplexPassword"
    okta_org_url = "https://mydomain.okta.com"
    okta_app_url = "https://mydomain/home/amazon_appstream/0oa8alauh3v3ise4C5d7/aln1al3ek55Es08M81d8"

    aws_role_arn = "arn:aws:iam::1234567890:role/Test_Role"
    aws_principal_arn = "arn:aws:iam::1234567890:saml-provider/Okta"
    target_role_arn = "arn:aws:iam::1234567890:role/Target_Long_Lived_Role"

    # 获取SAML断言
    saml_assertion = authenticate_with_okta(okta_username, okta_password, okta_org_url, okta_app_url)
    if not saml_assertion:
        print("获取SAML断言失败")
        return

    # 第一步:用SAML断言获取基础临时凭证
    try:
        base_credentials = assume_role_with_saml(saml_assertion, aws_role_arn, aws_principal_arn)
        print("基础临时凭证获取成功!")
    except Exception as e:
        print("扮演基础角色出错:", e)
        return

    # 第二步:用基础凭证扮演目标角色,获取超1小时有效期的凭证
    try:
        long_lived_credentials = assume_another_role(base_credentials, target_role_arn)
        print("长有效期临时凭证获取成功!")
        print("Access Key ID:", long_lived_credentials['AccessKeyId'])
        print("过期时间:", long_lived_credentials['Expiration'])
    except Exception as e:
        print("扮演目标角色出错:", e)

if __name__ == "__main__":
    main()

关键说明

  1. SAML断言获取逻辑:新增了用sessionToken访问Okta应用页面,解析HTML提取SAMLResponse的步骤,这才是AWS需要的合法SAML断言。
  2. 依赖补充:解析HTML需要beautifulsoup4库,Lambda环境需添加该依赖层或在部署时打包。
  3. 超1小时凭证实现:先用SAML获取1小时内的基础凭证,再用该凭证调用AssumeRole获取最长12小时的凭证,此方式不属于角色链(角色链指用IAM角色凭证再扮演角色),无角色链限制。
  4. 权限配置:目标角色的信任策略需允许基础角色扮演它,同时需在角色配置中开启允许最长12小时的会话有效期。

内容的提问来源于stack exchange,提问作者Piyush Pandey

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 16:24:57