使用Amazon SDK通过access_key/secret_key获取AWS凭证遇权限异常求助
问题现象
- 当
isUseProfile = true时,通过配置文件调用chain.TryGetAWSCredentials(profile, out awsCredentials)获取凭证,执行ssm:SendCommand操作正常,返回"Success"。 - 当
isUseProfile = false时,通过BasicAWSCredentials(accessKey, secretKey)创建凭证和客户端,执行相同操作抛出权限异常:
Error: User: arn:aws:iam::xxx:user/xxx-xxx-xxx is not authorized to perform: ssm:SendCommand on resource: arn:aws:ec2:region_endpoint:xxxxxx:instance/i-xxxxxxx because no identity-based policy allows the ssm:SendCommand action
已确认配置文件对应的凭证具备ssm:SendCommand权限,怀疑硬编码凭证的逻辑存在遗漏。
测试代码
public static async Task ConnectByAWSRunShellScript( string instanceId, string databaseHost, string databaseUsername, string databasePassword, string databaseName, RegionEndpoint regionEndpoint, string accessKey, string secretKey) { try { AWSCredentials awsCredentials; AmazonSimpleSystemsManagementClient ssmClient; bool isUseProfile = true; if (isUseProfile == true) { var profile = "profile_name"; var chain = new CredentialProfileStoreChain(); if (!chain.TryGetAWSCredentials(profile, out awsCredentials)) { Console.WriteLine("Failed to get AWS credentials"); return; } ssmClient = new AmazonSimpleSystemsManagementClient(awsCredentials); } else { awsCredentials = new BasicAWSCredentials(accessKey, secretKey); ssmClient = new AmazonSimpleSystemsManagementClient(awsCredentials); } var command = $"hostname"; var sendCommandRequest = new SendCommandRequest { InstanceIds = new List<string> { instanceId }, DocumentName = "AWS-RunShellScript", Parameters = new Dictionary<string, List<string>> { { "commands", new List<string> { command } } } }; var sendCommandResponse = await ssmClient.SendCommandAsync(sendCommandRequest); if (sendCommandResponse != null) { Console.WriteLine("Success"); } else { Console.WriteLine("Fail"); } } catch (Exception ex) { Console.WriteLine($"Error: {ex.Message}"); } }
问题分析与解决方案
1. 核对凭证一致性
检查硬编码的accessKey和secretKey是否与配置文件中profile_name对应的凭证完全一致。配置文件(通常在~/.aws/credentials或C:\Users\<User>\.aws\credentials)格式如下:
[profile_name] aws_access_key_id = YOUR_ACCESS_KEY aws_secret_access_key = YOUR_SECRET_KEY
如果两者不一致,会导致使用不同IAM用户,自然触发权限问题。
2. 显式指定区域参数
配置文件的config文件(~/.aws/config或对应Windows路径)可能为profile绑定了区域,而CredentialProfileStoreChain会自动加载该区域。但直接用BasicAWSCredentials创建客户端时,若未显式传入regionEndpoint,SDK会使用默认区域,若默认区域与目标实例区域不匹配,会导致请求发送到错误区域,进而触发权限异常。
修改第二种分支的客户端创建代码:
ssmClient = new AmazonSimpleSystemsManagementClient(awsCredentials, regionEndpoint);
3. 检查profile是否为角色配置
如果配置文件中的profile_name是角色而非IAM用户(比如通过STS角色假设),CredentialProfileStoreChain会自动调用STS获取临时凭证,此时临时凭证的权限来自角色而非原用户。若硬编码的是原用户的凭证,该用户可能仅具备角色假设权限,没有直接执行ssm:SendCommand的权限。
这种情况需改用STS假设角色的方式获取临时凭证:
var roleArn = "arn:aws:iam::xxx:role/your-role-name"; var stsClient = new AmazonSecurityTokenServiceClient(accessKey, secretKey); var assumeRoleRequest = new AssumeRoleRequest { RoleArn = roleArn, RoleSessionName = "test-session" }; var assumeRoleResponse = await stsClient.AssumeRoleAsync(assumeRoleRequest); var tempCredentials = new SessionAWSCredentials( assumeRoleResponse.Credentials.AccessKeyId, assumeRoleResponse.Credentials.SecretAccessKey, assumeRoleResponse.Credentials.SessionToken); ssmClient = new AmazonSimpleSystemsManagementClient(tempCredentials, regionEndpoint);
4. 验证IAM策略资源范围
检查硬编码凭证对应的IAM用户策略,确认ssm:SendCommand的资源是否包含目标实例的ARN,或使用通配符*。异常信息明确提示资源不匹配,若配置文件用的角色有更宽松的资源权限,而硬编码用户的策略资源范围有限,也会出现该问题。
快速验证步骤
在两种分支中添加代码,打印凭证对应的IAM身份ARN,确认是否为同一身份:
// 配置文件分支 var profileCreds = await awsCredentials.GetCredentialsAsync(); var iamClientProfile = new AmazonIdentityManagementServiceClient(awsCredentials); var profileUser = await iamClientProfile.GetUserAsync(); Console.WriteLine($"Profile User ARN: {profileUser.User.Arn}"); // 硬编码分支 var iamClientHardcode = new AmazonIdentityManagementServiceClient(awsCredentials, regionEndpoint); var hardcodeUser = await iamClientHardcode.GetUserAsync(); Console.WriteLine($"Hardcoded User ARN: {hardcodeUser.User.Arn}");
内容的提问来源于stack exchange,提问作者Mike

