使用 Amazon SDK for .NET 的 IAM 示例 - Amazon SDK for .NET
Amazon Web Services 文档中描述的 Amazon Web Services 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅 中国的 Amazon Web Services 服务入门 (PDF)

本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。

使用 Amazon SDK for .NET 的 IAM 示例

以下代码示例演示了如何将Amazon SDK for .NET 与 IAM 结合使用,以执行操作和实现常见场景。

操作是大型程序的代码摘录,必须在上下文中运行。您可以通过操作了解如何调用单个服务函数,还可以通过函数相关场景和跨服务示例的上下文查看操作。

场景是指显示如何通过在同一服务中调用多个函数来完成特定任务的代码示例。

每个示例都包含一个指向的链接 GitHub,您可以在其中找到有关如何在上下文中设置和运行代码的说明。

开始使用

以下代码示例演示了如何开始使用 IAM。

Amazon SDK for .NET
注意

还有更多相关信息 GitHub。在 Amazon 代码示例存储库中查找完整示例,了解如何进行设置和运行。

namespace IAMActions; public class HelloIAM { static async Task Main(string[] args) { // Getting started with AWS Identity and Access Management (IAM). List // the policies for the account. var iamClient = new AmazonIdentityManagementServiceClient(); var listPoliciesPaginator = iamClient.Paginators.ListPolicies(new ListPoliciesRequest()); var policies = new List<ManagedPolicy>(); await foreach (var response in listPoliciesPaginator.Responses) { policies.AddRange(response.Policies); } Console.WriteLine("Here are the policies defined for your account:\n"); policies.ForEach(policy => { Console.WriteLine($"Created: {policy.CreateDate}\t{policy.PolicyName}\t{policy.Description}"); }); } }
  • 有关 API 的详细信息,请参阅 Amazon SDK for .NETAPI 参考ListPolicies中的。

操作

以下代码示例显示如何将用户添加到 IAM 组。

Amazon SDK for .NET
注意

还有更多相关信息 GitHub。在 Amazon 代码示例存储库中查找完整示例,了解如何进行设置和运行。

/// <summary> /// Add an existing IAM user to an existing IAM group. /// </summary> /// <param name="userName">The username of the user to add.</param> /// <param name="groupName">The name of the group to add the user to.</param> /// <returns>A Boolean value indicating the success of the action.</returns> public async Task<bool> AddUserToGroupAsync(string userName, string groupName) { var response = await _IAMService.AddUserToGroupAsync(new AddUserToGroupRequest { GroupName = groupName, UserName = userName, }); return response.HttpStatusCode == HttpStatusCode.OK; }
  • 有关 API 的详细信息,请参阅 Amazon SDK for .NETAPI 参考AddUserToGroup中的。

以下代码示例演示了如何将 IAM 策略添加到角色。

Amazon SDK for .NET
注意

还有更多相关信息 GitHub。在 Amazon 代码示例存储库中查找完整示例,了解如何进行设置和运行。

/// <summary> /// Attach an IAM policy to a role. /// </summary> /// <param name="policyArn">The policy to attach.</param> /// <param name="roleName">The role that the policy will be attached to.</param> /// <returns>A Boolean value indicating the success of the action.</returns> public async Task<bool> AttachRolePolicyAsync(string policyArn, string roleName) { var response = await _IAMService.AttachRolePolicyAsync(new AttachRolePolicyRequest { PolicyArn = policyArn, RoleName = roleName, }); return response.HttpStatusCode == System.Net.HttpStatusCode.OK; }
  • 有关 API 的详细信息,请参阅 Amazon SDK for .NETAPI 参考AttachRolePolicy中的。

以下代码示例演示了如何将内联策略附加到 IAM 角色。

Amazon SDK for .NET
注意

还有更多相关信息 GitHub。在 Amazon 代码示例存储库中查找完整示例,了解如何进行设置和运行。

/// <summary> /// Update the inline policy document embedded in a role. /// </summary> /// <param name="policyName">The name of the policy to embed.</param> /// <param name="roleName">The name of the role to update.</param> /// <param name="policyDocument">The policy document that defines the role.</param> /// <returns>A Boolean value indicating the success of the action.</returns> public async Task<bool> PutRolePolicyAsync(string policyName, string roleName, string policyDocument) { var request = new PutRolePolicyRequest { PolicyName = policyName, RoleName = roleName, PolicyDocument = policyDocument }; var response = await _IAMService.PutRolePolicyAsync(request); return response.HttpStatusCode == HttpStatusCode.OK; }
  • 有关 API 的详细信息,请参阅 Amazon SDK for .NETAPI 参考PutRolePolicy中的。

以下代码示例演示了如何创建 IAM 组。

Amazon SDK for .NET
注意

还有更多相关信息 GitHub。在 Amazon 代码示例存储库中查找完整示例,了解如何进行设置和运行。

/// <summary> /// Create an IAM group. /// </summary> /// <param name="groupName">The name to give the IAM group.</param> /// <returns>The IAM group that was created.</returns> public async Task<Group> CreateGroupAsync(string groupName) { var response = await _IAMService.CreateGroupAsync(new CreateGroupRequest { GroupName = groupName }); return response.Group; }
  • 有关 API 的详细信息,请参阅 Amazon SDK for .NETAPI 参考CreateGroup中的。

以下代码示例演示如何创建 IAM 策略。

Amazon SDK for .NET
注意

还有更多相关信息 GitHub。在 Amazon 代码示例存储库中查找完整示例,了解如何进行设置和运行。

/// <summary> /// Create an IAM policy. /// </summary> /// <param name="policyName">The name to give the new IAM policy.</param> /// <param name="policyDocument">The policy document for the new policy.</param> /// <returns>The new IAM policy object.</returns> public async Task<ManagedPolicy> CreatePolicyAsync(string policyName, string policyDocument) { var response = await _IAMService.CreatePolicyAsync(new CreatePolicyRequest { PolicyDocument = policyDocument, PolicyName = policyName, }); return response.Policy; }
  • 有关 API 的详细信息,请参阅 Amazon SDK for .NETAPI 参考CreatePolicy中的。

以下代码示例演示了如何创建 IAM 角色。

Amazon SDK for .NET
注意

还有更多相关信息 GitHub。在 Amazon 代码示例存储库中查找完整示例,了解如何进行设置和运行。

/// <summary> /// Create a new IAM role. /// </summary> /// <param name="roleName">The name of the IAM role.</param> /// <param name="rolePolicyDocument">The name of the IAM policy document /// for the new role.</param> /// <returns>The Amazon Resource Name (ARN) of the role.</returns> public async Task<string> CreateRoleAsync(string roleName, string rolePolicyDocument) { var request = new CreateRoleRequest { RoleName = roleName, AssumeRolePolicyDocument = rolePolicyDocument, }; var response = await _IAMService.CreateRoleAsync(request); return response.Role.Arn; }
  • 有关 API 的详细信息,请参阅 Amazon SDK for .NETAPI 参考CreateRole中的。

以下代码示例演示了如何创建 IAM 服务相关角色。

Amazon SDK for .NET
注意

还有更多相关信息 GitHub。在 Amazon 代码示例存储库中查找完整示例,了解如何进行设置和运行。

/// <summary> /// Create an IAM service-linked role. /// </summary> /// <param name="serviceName">The name of the AWS Service.</param> /// <param name="description">A description of the IAM service-linked role.</param> /// <returns>The IAM role that was created.</returns> public async Task<Role> CreateServiceLinkedRoleAsync(string serviceName, string description) { var request = new CreateServiceLinkedRoleRequest { AWSServiceName = serviceName, Description = description }; var response = await _IAMService.CreateServiceLinkedRoleAsync(request); return response.Role; }

以下代码示例演示了如何创建 IAM 用户。

警告

为了避免安全风险,在开发专用软件或处理真实数据时,请勿使用 IAM 用户进行身份验证,而是使用与身份提供商的联合身份验证,例如 Amazon IAM Identity Center

Amazon SDK for .NET
注意

还有更多相关信息 GitHub。在 Amazon 代码示例存储库中查找完整示例,了解如何进行设置和运行。

/// <summary> /// Create an IAM user. /// </summary> /// <param name="userName">The username for the new IAM user.</param> /// <returns>The IAM user that was created.</returns> public async Task<User> CreateUserAsync(string userName) { var response = await _IAMService.CreateUserAsync(new CreateUserRequest { UserName = userName }); return response.User; }
  • 有关 API 的详细信息,请参阅 Amazon SDK for .NETAPI 参考CreateUser中的。

以下代码示例演示了如何创建 IAM 访问密钥。

警告

为了避免安全风险,在开发专用软件或处理真实数据时,请勿使用 IAM 用户进行身份验证,而是使用与身份提供商的联合身份验证,例如 Amazon IAM Identity Center

Amazon SDK for .NET
注意

还有更多相关信息 GitHub。在 Amazon 代码示例存储库中查找完整示例,了解如何进行设置和运行。

/// <summary> /// Create an IAM access key for a user. /// </summary> /// <param name="userName">The username for which to create the IAM access /// key.</param> /// <returns>The AccessKey.</returns> public async Task<AccessKey> CreateAccessKeyAsync(string userName) { var response = await _IAMService.CreateAccessKeyAsync(new CreateAccessKeyRequest { UserName = userName, }); return response.AccessKey; }
  • 有关 API 的详细信息,请参阅 Amazon SDK for .NETAPI 参考CreateAccessKey中的。

以下代码示例演示了如何为组创建内联 IAM policy。

Amazon SDK for .NET
注意

还有更多相关信息 GitHub。在 Amazon 代码示例存储库中查找完整示例,了解如何进行设置和运行。

/// <summary> /// Add or update an inline policy document that is embedded in an IAM group. /// </summary> /// <param name="groupName">The name of the IAM group.</param> /// <param name="policyName">The name of the IAM policy.</param> /// <param name="policyDocument">The policy document defining the IAM policy.</param> /// <returns>A Boolean value indicating the success of the action.</returns> public async Task<bool> PutGroupPolicyAsync(string groupName, string policyName, string policyDocument) { var request = new PutGroupPolicyRequest { GroupName = groupName, PolicyName = policyName, PolicyDocument = policyDocument }; var response = await _IAMService.PutGroupPolicyAsync(request); return response.HttpStatusCode == System.Net.HttpStatusCode.OK; }
  • 有关 API 的详细信息,请参阅 Amazon SDK for .NETAPI 参考PutGroupPolicy中的。

以下代码示例演示了如何创建 IAM 实例配置文件。

Amazon SDK for .NET
注意

还有更多相关信息 GitHub。在 Amazon 代码示例存储库中查找完整示例,了解如何进行设置和运行。

/// <summary> /// Create a policy, role, and profile that is associated with instances with a specified name. /// An instance's associated profile defines a role that is assumed by the /// instance.The role has attached policies that specify the AWS permissions granted to /// clients that run on the instance. /// </summary> /// <param name="policyName">Name to use for the policy.</param> /// <param name="roleName">Name to use for the role.</param> /// <param name="profileName">Name to use for the profile.</param> /// <param name="ssmOnlyPolicyFile">Path to a policy file for SSM.</param> /// <param name="awsManagedPolicies">AWS Managed policies to be attached to the role.</param> /// <returns>The Arn of the profile.</returns> public async Task<string> CreateInstanceProfileWithName( string policyName, string roleName, string profileName, string ssmOnlyPolicyFile, List<string>? awsManagedPolicies = null) { var assumeRoleDoc = "{" + "\"Version\": \"2012-10-17\"," + "\"Statement\": [{" + "\"Effect\": \"Allow\"," + "\"Principal\": {" + "\"Service\": [" + "\"ec2.amazonaws.com\"" + "]" + "}," + "\"Action\": \"sts:AssumeRole\"" + "}]" + "}"; var policyDocument = await File.ReadAllTextAsync(ssmOnlyPolicyFile); var policyArn = ""; try { var createPolicyResult = await _amazonIam.CreatePolicyAsync( new CreatePolicyRequest { PolicyName = policyName, PolicyDocument = policyDocument }); policyArn = createPolicyResult.Policy.Arn; } catch (EntityAlreadyExistsException) { // The policy already exists, so we look it up to get the Arn. var policiesPaginator = _amazonIam.Paginators.ListPolicies( new ListPoliciesRequest() { Scope = PolicyScopeType.Local }); // Get the entire list using the paginator. await foreach (var policy in policiesPaginator.Policies) { if (policy.PolicyName.Equals(policyName)) { policyArn = policy.Arn; } } if (policyArn == null) { throw new InvalidOperationException("Policy not found"); } } try { await _amazonIam.CreateRoleAsync(new CreateRoleRequest() { RoleName = roleName, AssumeRolePolicyDocument = assumeRoleDoc, }); await _amazonIam.AttachRolePolicyAsync(new AttachRolePolicyRequest() { RoleName = roleName, PolicyArn = policyArn }); if (awsManagedPolicies != null) { foreach (var awsPolicy in awsManagedPolicies) { await _amazonIam.AttachRolePolicyAsync(new AttachRolePolicyRequest() { PolicyArn = $"arn:aws:iam::aws:policy/{awsPolicy}", RoleName = roleName }); } } } catch (EntityAlreadyExistsException) { Console.WriteLine("Role already exists."); } string profileArn = ""; try { var profileCreateResponse = await _amazonIam.CreateInstanceProfileAsync( new CreateInstanceProfileRequest() { InstanceProfileName = profileName }); // Allow time for the profile to be ready. profileArn = profileCreateResponse.InstanceProfile.Arn; Thread.Sleep(10000); await _amazonIam.AddRoleToInstanceProfileAsync( new AddRoleToInstanceProfileRequest() { InstanceProfileName = profileName, RoleName = roleName }); } catch (EntityAlreadyExistsException) { Console.WriteLine("Policy already exists."); var profileGetResponse = await _amazonIam.GetInstanceProfileAsync( new GetInstanceProfileRequest() { InstanceProfileName = profileName }); profileArn = profileGetResponse.InstanceProfile.Arn; } return profileArn; }

以下代码示例演示了如何删除 IAM 组。

Amazon SDK for .NET
注意

还有更多相关信息 GitHub。在 Amazon 代码示例存储库中查找完整示例,了解如何进行设置和运行。

/// <summary> /// Delete an IAM group. /// </summary> /// <param name="groupName">The name of the IAM group to delete.</param> /// <returns>A Boolean value indicating the success of the action.</returns> public async Task<bool> DeleteGroupAsync(string groupName) { var response = await _IAMService.DeleteGroupAsync(new DeleteGroupRequest { GroupName = groupName }); return response.HttpStatusCode == HttpStatusCode.OK; }
  • 有关 API 的详细信息,请参阅 Amazon SDK for .NETAPI 参考DeleteGroup中的。

以下代码示例显示如何删除 IAM 组策略。

Amazon SDK for .NET
注意

还有更多相关信息 GitHub。在 Amazon 代码示例存储库中查找完整示例,了解如何进行设置和运行。

/// <summary> /// Delete an IAM policy associated with an IAM group. /// </summary> /// <param name="groupName">The name of the IAM group associated with the /// policy.</param> /// <param name="policyName">The name of the policy to delete.</param> /// <returns>A Boolean value indicating the success of the action.</returns> public async Task<bool> DeleteGroupPolicyAsync(string groupName, string policyName) { var request = new DeleteGroupPolicyRequest() { GroupName = groupName, PolicyName = policyName, }; var response = await _IAMService.DeleteGroupPolicyAsync(request); return response.HttpStatusCode == System.Net.HttpStatusCode.OK; }
  • 有关 API 的详细信息,请参阅 Amazon SDK for .NETAPI 参考DeleteGroupPolicy中的。

以下代码示例演示如何删除 IAM 策略。

Amazon SDK for .NET
注意

还有更多相关信息 GitHub。在 Amazon 代码示例存储库中查找完整示例,了解如何进行设置和运行。

/// <summary> /// Delete an IAM policy. /// </summary> /// <param name="policyArn">The Amazon Resource Name (ARN) of the policy to /// delete.</param> /// <returns>A Boolean value indicating the success of the action.</returns> public async Task<bool> DeletePolicyAsync(string policyArn) { var response = await _IAMService.DeletePolicyAsync(new DeletePolicyRequest { PolicyArn = policyArn }); return response.HttpStatusCode == System.Net.HttpStatusCode.OK; }
  • 有关 API 的详细信息,请参阅 Amazon SDK for .NETAPI 参考DeletePolicy中的。

以下代码示例演示了如何删除 IAM 角色。

Amazon SDK for .NET
注意

还有更多相关信息 GitHub。在 Amazon 代码示例存储库中查找完整示例,了解如何进行设置和运行。

/// <summary> /// Delete an IAM role. /// </summary> /// <param name="roleName">The name of the IAM role to delete.</param> /// <returns>A Boolean value indicating the success of the action.</returns> public async Task<bool> DeleteRoleAsync(string roleName) { var response = await _IAMService.DeleteRoleAsync(new DeleteRoleRequest { RoleName = roleName }); return response.HttpStatusCode == System.Net.HttpStatusCode.OK; }
  • 有关 API 的详细信息,请参阅 Amazon SDK for .NETAPI 参考DeleteRole中的。

以下代码示例演示了如何删除 IAM 角色策略。

Amazon SDK for .NET
注意

还有更多相关信息 GitHub。在 Amazon 代码示例存储库中查找完整示例,了解如何进行设置和运行。

/// <summary> /// Delete an IAM role policy. /// </summary> /// <param name="roleName">The name of the IAM role.</param> /// <param name="policyName">The name of the IAM role policy to delete.</param> /// <returns>A Boolean value indicating the success of the action.</returns> public async Task<bool> DeleteRolePolicyAsync(string roleName, string policyName) { var response = await _IAMService.DeleteRolePolicyAsync(new DeleteRolePolicyRequest { PolicyName = policyName, RoleName = roleName, }); return response.HttpStatusCode == System.Net.HttpStatusCode.OK; }
  • 有关 API 的详细信息,请参阅 Amazon SDK for .NETAPI 参考DeleteRolePolicy中的。

以下代码示例演示了如何删除 IAM 用户。

警告

为了避免安全风险,在开发专用软件或处理真实数据时,请勿使用 IAM 用户进行身份验证,而是使用与身份提供商的联合身份验证,例如 Amazon IAM Identity Center

Amazon SDK for .NET
注意

还有更多相关信息 GitHub。在 Amazon 代码示例存储库中查找完整示例,了解如何进行设置和运行。

/// <summary> /// Delete an IAM user. /// </summary> /// <param name="userName">The username of the IAM user to delete.</param> /// <returns>A Boolean value indicating the success of the action.</returns> public async Task<bool> DeleteUserAsync(string userName) { var response = await _IAMService.DeleteUserAsync(new DeleteUserRequest { UserName = userName }); return response.HttpStatusCode == System.Net.HttpStatusCode.OK; }
  • 有关 API 的详细信息,请参阅 Amazon SDK for .NETAPI 参考DeleteUser中的。

以下代码示例演示了如何删除 IAM 访问密钥。

警告

为了避免安全风险,在开发专用软件或处理真实数据时,请勿使用 IAM 用户进行身份验证,而是使用与身份提供商的联合身份验证,例如 Amazon IAM Identity Center

Amazon SDK for .NET
注意

还有更多相关信息 GitHub。在 Amazon 代码示例存储库中查找完整示例,了解如何进行设置和运行。

/// <summary> /// Delete an IAM user's access key. /// </summary> /// <param name="accessKeyId">The Id for the IAM access key.</param> /// <param name="userName">The username of the user that owns the IAM /// access key.</param> /// <returns>A Boolean value indicating the success of the action.</returns> public async Task<bool> DeleteAccessKeyAsync(string accessKeyId, string userName) { var response = await _IAMService.DeleteAccessKeyAsync(new DeleteAccessKeyRequest { AccessKeyId = accessKeyId, UserName = userName, }); return response.HttpStatusCode == System.Net.HttpStatusCode.OK; }
  • 有关 API 的详细信息,请参阅 Amazon SDK for .NETAPI 参考DeleteAccessKey中的。

以下代码示例演示如何删除用户的内联 IAM 策略。

警告

为了避免安全风险,在开发专用软件或处理真实数据时,请勿使用 IAM 用户进行身份验证,而是使用与身份提供商的联合身份验证,例如 Amazon IAM Identity Center

Amazon SDK for .NET
注意

还有更多相关信息 GitHub。在 Amazon 代码示例存储库中查找完整示例,了解如何进行设置和运行。

/// <summary> /// Delete an IAM user policy. /// </summary> /// <param name="policyName">The name of the IAM policy to delete.</param> /// <param name="userName">The username of the IAM user.</param> /// <returns>A Boolean value indicating the success of the action.</returns> public async Task<bool> DeleteUserPolicyAsync(string policyName, string userName) { var response = await _IAMService.DeleteUserPolicyAsync(new DeleteUserPolicyRequest { PolicyName = policyName, UserName = userName }); return response.HttpStatusCode == System.Net.HttpStatusCode.OK; }
  • 有关 API 的详细信息,请参阅 Amazon SDK for .NETAPI 参考DeleteUserPolicy中的。

以下代码示例演示了如何删除 IAM 实例配置文件。

Amazon SDK for .NET
注意

还有更多相关信息 GitHub。在 Amazon 代码示例存储库中查找完整示例,了解如何进行设置和运行。

/// <summary> /// Detaches a role from an instance profile, detaches policies from the role, /// and deletes all the resources. /// </summary> /// <param name="profileName">The name of the profile to delete.</param> /// <param name="roleName">The name of the role to delete.</param> /// <returns>Async task.</returns> public async Task DeleteInstanceProfile(string profileName, string roleName) { try { await _amazonIam.RemoveRoleFromInstanceProfileAsync( new RemoveRoleFromInstanceProfileRequest() { InstanceProfileName = profileName, RoleName = roleName }); await _amazonIam.DeleteInstanceProfileAsync( new DeleteInstanceProfileRequest() { InstanceProfileName = profileName }); var attachedPolicies = await _amazonIam.ListAttachedRolePoliciesAsync( new ListAttachedRolePoliciesRequest() { RoleName = roleName }); foreach (var policy in attachedPolicies.AttachedPolicies) { await _amazonIam.DetachRolePolicyAsync( new DetachRolePolicyRequest() { RoleName = roleName, PolicyArn = policy.PolicyArn }); // Delete the custom policies only. if (!policy.PolicyArn.StartsWith("arn:aws:iam::aws")) { await _amazonIam.DeletePolicyAsync( new Amazon.IdentityManagement.Model.DeletePolicyRequest() { PolicyArn = policy.PolicyArn }); } } await _amazonIam.DeleteRoleAsync( new DeleteRoleRequest() { RoleName = roleName }); } catch (NoSuchEntityException) { Console.WriteLine($"Instance profile {profileName} does not exist."); } }

以下代码示例演示了如何从角色分离 IAM 策略。

Amazon SDK for .NET
注意

还有更多相关信息 GitHub。在 Amazon 代码示例存储库中查找完整示例,了解如何进行设置和运行。

/// <summary> /// Detach an IAM policy from an IAM role. /// </summary> /// <param name="policyArn">The Amazon Resource Name (ARN) of the IAM policy.</param> /// <param name="roleName">The name of the IAM role.</param> /// <returns>A Boolean value indicating the success of the action.</returns> public async Task<bool> DetachRolePolicyAsync(string policyArn, string roleName) { var response = await _IAMService.DetachRolePolicyAsync(new DetachRolePolicyRequest { PolicyArn = policyArn, RoleName = roleName, }); return response.HttpStatusCode == System.Net.HttpStatusCode.OK; }
  • 有关 API 的详细信息,请参阅 Amazon SDK for .NETAPI 参考DetachRolePolicy中的。

以下代码示例演示了如何获取 IAM 策略。

Amazon SDK for .NET
注意

还有更多相关信息 GitHub。在 Amazon 代码示例存储库中查找完整示例,了解如何进行设置和运行。

/// <summary> /// Get information about an IAM policy. /// </summary> /// <param name="policyArn">The IAM policy to retrieve information for.</param> /// <returns>The IAM policy.</returns> public async Task<ManagedPolicy> GetPolicyAsync(string policyArn) { var response = await _IAMService.GetPolicyAsync(new GetPolicyRequest { PolicyArn = policyArn }); return response.Policy; }
  • 有关 API 的详细信息,请参阅 Amazon SDK for .NETAPI 参考GetPolicy中的。

以下代码示例演示了如何获取 IAM 角色。

Amazon SDK for .NET
注意

还有更多相关信息 GitHub。在 Amazon 代码示例存储库中查找完整示例,了解如何进行设置和运行。

/// <summary> /// Get information about an IAM role. /// </summary> /// <param name="roleName">The name of the IAM role to retrieve information /// for.</param> /// <returns>The IAM role that was retrieved.</returns> public async Task<Role> GetRoleAsync(string roleName) { var response = await _IAMService.GetRoleAsync(new GetRoleRequest { RoleName = roleName, }); return response.Role; }
  • 有关 API 的详细信息,请参阅 Amazon SDK for .NETAPI 参考GetRole中的。

以下代码示例显示如何获取 IAM 用户。

警告

为了避免安全风险,在开发专用软件或处理真实数据时,请勿使用 IAM 用户进行身份验证,而是使用与身份提供商的联合身份验证,例如 Amazon IAM Identity Center

Amazon SDK for .NET
注意

还有更多相关信息 GitHub。在 Amazon 代码示例存储库中查找完整示例,了解如何进行设置和运行。

/// <summary> /// Get information about an IAM user. /// </summary> /// <param name="userName">The username of the user.</param> /// <returns>An IAM user object.</returns> public async Task<User> GetUserAsync(string userName) { var response = await _IAMService.GetUserAsync(new GetUserRequest { UserName = userName }); return response.User; }
  • 有关 API 的详细信息,请参阅 Amazon SDK for .NETAPI 参考GetUser中的。

以下代码示例演示了如何获取 IAM 账户密码策略。

Amazon SDK for .NET
注意

还有更多相关信息 GitHub。在 Amazon 代码示例存储库中查找完整示例,了解如何进行设置和运行。

/// <summary> /// Gets the IAM password policy for an AWS account. /// </summary> /// <returns>The PasswordPolicy for the AWS account.</returns> public async Task<PasswordPolicy> GetAccountPasswordPolicyAsync() { var response = await _IAMService.GetAccountPasswordPolicyAsync(new GetAccountPasswordPolicyRequest()); return response.PasswordPolicy; }

以下代码示例演示了如何列出 IAM 的 SAML 提供商。

Amazon SDK for .NET
注意

还有更多相关信息 GitHub。查找完整示例,了解如何在 Amazon 代码示例存储库中进行设置和运行。

/// <summary> /// List SAML authentication providers. /// </summary> /// <returns>A list of SAML providers.</returns> public async Task<List<SAMLProviderListEntry>> ListSAMLProvidersAsync() { var response = await _IAMService.ListSAMLProvidersAsync(new ListSAMLProvidersRequest()); return response.SAMLProviderList; }
  • 有关 API 详细信息,请参阅 Amazon SDK for .NET API 参考中的 ListSAMLProviders

以下代码示例演示了如何列出 IAM 组。

Amazon SDK for .NET
注意

还有更多相关信息 GitHub。在 Amazon 代码示例存储库中查找完整示例,了解如何进行设置和运行。

/// <summary> /// List IAM groups. /// </summary> /// <returns>A list of IAM groups.</returns> public async Task<List<Group>> ListGroupsAsync() { var groupsPaginator = _IAMService.Paginators.ListGroups(new ListGroupsRequest()); var groups = new List<Group>(); await foreach (var response in groupsPaginator.Responses) { groups.AddRange(response.Groups); } return groups; }
  • 有关 API 的详细信息,请参阅 Amazon SDK for .NETAPI 参考ListGroups中的。

以下代码示例演示了如何列出 IAM 角色的内联策略。

Amazon SDK for .NET
注意

还有更多相关信息 GitHub。在 Amazon 代码示例存储库中查找完整示例,了解如何进行设置和运行。

/// <summary> /// List IAM role policies. /// </summary> /// <param name="roleName">The IAM role for which to list IAM policies.</param> /// <returns>A list of IAM policy names.</returns> public async Task<List<string>> ListRolePoliciesAsync(string roleName) { var listRolePoliciesPaginator = _IAMService.Paginators.ListRolePolicies(new ListRolePoliciesRequest { RoleName = roleName }); var policyNames = new List<string>(); await foreach (var response in listRolePoliciesPaginator.Responses) { policyNames.AddRange(response.PolicyNames); } return policyNames; }
  • 有关 API 的详细信息,请参阅 Amazon SDK for .NETAPI 参考ListRolePolicies中的。

以下代码示例演示了如何列出 IAM 策略。

Amazon SDK for .NET
注意

还有更多相关信息 GitHub。在 Amazon 代码示例存储库中查找完整示例,了解如何进行设置和运行。

/// <summary> /// List IAM policies. /// </summary> /// <returns>A list of the IAM policies.</returns> public async Task<List<ManagedPolicy>> ListPoliciesAsync() { var listPoliciesPaginator = _IAMService.Paginators.ListPolicies(new ListPoliciesRequest()); var policies = new List<ManagedPolicy>(); await foreach (var response in listPoliciesPaginator.Responses) { policies.AddRange(response.Policies); } return policies; }
  • 有关 API 的详细信息,请参阅 Amazon SDK for .NETAPI 参考ListPolicies中的。

以下代码示例演示了如何列出附加到 IAM 角色的策略。

Amazon SDK for .NET
注意

还有更多相关信息 GitHub。在 Amazon 代码示例存储库中查找完整示例,了解如何进行设置和运行。

/// <summary> /// List the IAM role policies that are attached to an IAM role. /// </summary> /// <param name="roleName">The IAM role to list IAM policies for.</param> /// <returns>A list of the IAM policies attached to the IAM role.</returns> public async Task<List<AttachedPolicyType>> ListAttachedRolePoliciesAsync(string roleName) { var attachedPolicies = new List<AttachedPolicyType>(); var attachedRolePoliciesPaginator = _IAMService.Paginators.ListAttachedRolePolicies(new ListAttachedRolePoliciesRequest { RoleName = roleName }); await foreach (var response in attachedRolePoliciesPaginator.Responses) { attachedPolicies.AddRange(response.AttachedPolicies); } return attachedPolicies; }

以下代码示例演示了如何列出 IAM 角色。

Amazon SDK for .NET
注意

还有更多相关信息 GitHub。在 Amazon 代码示例存储库中查找完整示例,了解如何进行设置和运行。

/// <summary> /// List IAM roles. /// </summary> /// <returns>A list of IAM roles.</returns> public async Task<List<Role>> ListRolesAsync() { var listRolesPaginator = _IAMService.Paginators.ListRoles(new ListRolesRequest()); var roles = new List<Role>(); await foreach (var response in listRolesPaginator.Responses) { roles.AddRange(response.Roles); } return roles; }
  • 有关 API 的详细信息,请参阅 Amazon SDK for .NETAPI 参考ListRoles中的。

以下代码示例演示了如何列出 IAM 用户。

警告

为了避免安全风险,在开发专用软件或处理真实数据时,请勿使用 IAM 用户进行身份验证,而是使用与身份提供商的联合身份验证,例如 Amazon IAM Identity Center

Amazon SDK for .NET
注意

还有更多相关信息 GitHub。在 Amazon 代码示例存储库中查找完整示例,了解如何进行设置和运行。

/// <summary> /// List IAM users. /// </summary> /// <returns>A list of IAM users.</returns> public async Task<List<User>> ListUsersAsync() { var listUsersPaginator = _IAMService.Paginators.ListUsers(new ListUsersRequest()); var users = new List<User>(); await foreach (var response in listUsersPaginator.Responses) { users.AddRange(response.Users); } return users; }
  • 有关 API 的详细信息,请参阅 Amazon SDK for .NETAPI 参考ListUsers中的。

以下代码示例显示如何从 IAM 组中删除用户。

Amazon SDK for .NET
注意

还有更多相关信息 GitHub。在 Amazon 代码示例存储库中查找完整示例,了解如何进行设置和运行。

/// <summary> /// Remove a user from an IAM group. /// </summary> /// <param name="userName">The username of the user to remove.</param> /// <param name="groupName">The name of the IAM group to remove the user from.</param> /// <returns>A Boolean value indicating the success of the action.</returns> public async Task<bool> RemoveUserFromGroupAsync(string userName, string groupName) { // Remove the user from the group. var removeUserRequest = new RemoveUserFromGroupRequest() { UserName = userName, GroupName = groupName, }; var response = await _IAMService.RemoveUserFromGroupAsync(removeUserRequest); return response.HttpStatusCode == HttpStatusCode.OK; }
  • 有关 API 的详细信息,请参阅 Amazon SDK for .NETAPI 参考RemoveUserFromGroup中的。

场景

以下代码示例演示了如何创建可返回书籍、电影和歌曲推荐的负载均衡的 Web 服务。该示例演示服务如何响应故障,以及如何重组服务以提高故障发生时的弹性。

  • 使用 Amazon EC2 Auto Scaling 组根据启动模板创建 Amazon Elastic Compute Cloud(Amazon EC2)实例,并将实例数量保持在指定范围内。

  • 使用弹性负载均衡处理和分发 HTTP 请求。

  • 监控自动扩缩组中实例的运行状况,并仅将请求转发到运行状况良好的实例。

  • 在每个 EC2 实例上运行 Python Web 服务器以处理 HTTP 请求。Web 服务器以建议和运行状况检查作为响应。

  • 使用 Amazon DynamoDB 表模拟推荐服务。

  • 通过更新 Amazon Systems Manager 参数控制 Web 服务器对请求和运行状况检查的响应。

Amazon SDK for .NET
注意

还有更多相关信息 GitHub。在 Amazon 代码示例存储库中查找完整示例,了解如何进行设置和运行。

在命令提示符中运行交互式场景。

static async Task Main(string[] args) { _configuration = new ConfigurationBuilder() .SetBasePath(Directory.GetCurrentDirectory()) .AddJsonFile("settings.json") // Load settings from .json file. .AddJsonFile("settings.local.json", true) // Optionally, load local settings. .Build(); // Set up dependency injection for the AWS services. using var host = Host.CreateDefaultBuilder(args) .ConfigureLogging(logging => logging.AddFilter("System", LogLevel.Debug) .AddFilter<DebugLoggerProvider>("Microsoft", LogLevel.Information) .AddFilter<ConsoleLoggerProvider>("Microsoft", LogLevel.Trace)) .ConfigureServices((_, services) => services.AddAWSService<IAmazonIdentityManagementService>() .AddAWSService<IAmazonDynamoDB>() .AddAWSService<IAmazonElasticLoadBalancingV2>() .AddAWSService<IAmazonSimpleSystemsManagement>() .AddAWSService<IAmazonAutoScaling>() .AddAWSService<IAmazonEC2>() .AddTransient<AutoScalerWrapper>() .AddTransient<ElasticLoadBalancerWrapper>() .AddTransient<SmParameterWrapper>() .AddTransient<Recommendations>() .AddSingleton<IConfiguration>(_configuration) ) .Build(); ServicesSetup(host); ResourcesSetup(); try { Console.WriteLine(new string('-', 80)); Console.WriteLine("Welcome to the Resilient Architecture Example Scenario."); Console.WriteLine(new string('-', 80)); await Deploy(true); Console.WriteLine("Now let's begin the scenario."); Console.WriteLine(new string('-', 80)); await Demo(true); Console.WriteLine(new string('-', 80)); Console.WriteLine("Finally, let's clean up our resources."); Console.WriteLine(new string('-', 80)); await DestroyResources(true); Console.WriteLine(new string('-', 80)); Console.WriteLine("Resilient Architecture Example Scenario is complete."); Console.WriteLine(new string('-', 80)); } catch (Exception ex) { Console.WriteLine(new string('-', 80)); Console.WriteLine($"There was a problem running the scenario: {ex.Message}"); await DestroyResources(true); Console.WriteLine(new string('-', 80)); } } /// <summary> /// Setup any common resources, also used for integration testing. /// </summary> public static void ResourcesSetup() { _httpClient = new HttpClient(); } /// <summary> /// Populate the services for use within the console application. /// </summary> /// <param name="host">The services host.</param> private static void ServicesSetup(IHost host) { _elasticLoadBalancerWrapper = host.Services.GetRequiredService<ElasticLoadBalancerWrapper>(); _iamClient = host.Services.GetRequiredService<IAmazonIdentityManagementService>(); _recommendations = host.Services.GetRequiredService<Recommendations>(); _autoScalerWrapper = host.Services.GetRequiredService<AutoScalerWrapper>(); _smParameterWrapper = host.Services.GetRequiredService<SmParameterWrapper>(); } /// <summary> /// Deploy necessary resources for the scenario. /// </summary> /// <param name="interactive">True to run as interactive.</param> /// <returns>True if successful.</returns> public static async Task<bool> Deploy(bool interactive) { var protocol = "HTTP"; var port = 80; var sshPort = 22; Console.WriteLine( "\nFor this demo, we'll use the AWS SDK for .NET to create several AWS resources\n" + "to set up a load-balanced web service endpoint and explore some ways to make it resilient\n" + "against various kinds of failures.\n\n" + "Some of the resources create by this demo are:\n"); Console.WriteLine( "\t* A DynamoDB table that the web service depends on to provide book, movie, and song recommendations."); Console.WriteLine( "\t* An EC2 launch template that defines EC2 instances that each contain a Python web server."); Console.WriteLine( "\t* An EC2 Auto Scaling group that manages EC2 instances across several Availability Zones."); Console.WriteLine( "\t* An Elastic Load Balancing (ELB) load balancer that targets the Auto Scaling group to distribute requests."); Console.WriteLine(new string('-', 80)); Console.WriteLine("Press Enter when you're ready to start deploying resources."); if (interactive) Console.ReadLine(); // Create and populate the DynamoDB table. var databaseTableName = _configuration["databaseName"]; var recommendationsPath = Path.Join(_configuration["resourcePath"], "recommendations_objects.json"); Console.WriteLine($"Creating and populating a DynamoDB table named {databaseTableName}."); await _recommendations.CreateDatabaseWithName(databaseTableName); await _recommendations.PopulateDatabase(databaseTableName, recommendationsPath); Console.WriteLine(new string('-', 80)); // Create the EC2 Launch Template. Console.WriteLine( $"Creating an EC2 launch template that runs 'server_startup_script.sh' when an instance starts.\n" + "\nThis script starts a Python web server defined in the `server.py` script. The web server\n" + "listens to HTTP requests on port 80 and responds to requests to '/' and to '/healthcheck'.\n" + "For demo purposes, this server is run as the root user. In production, the best practice is to\n" + "run a web server, such as Apache, with least-privileged credentials."); Console.WriteLine( "\nThe template also defines an IAM policy that each instance uses to assume a role that grants\n" + "permissions to access the DynamoDB recommendation table and Systems Manager parameters\n" + "that control the flow of the demo."); var startupScriptPath = Path.Join(_configuration["resourcePath"], "server_startup_script.sh"); var instancePolicyPath = Path.Join(_configuration["resourcePath"], "instance_policy.json"); await _autoScalerWrapper.CreateTemplate(startupScriptPath, instancePolicyPath); Console.WriteLine(new string('-', 80)); Console.WriteLine( "Creating an EC2 Auto Scaling group that maintains three EC2 instances, each in a different\n" + "Availability Zone.\n"); var zones = await _autoScalerWrapper.DescribeAvailabilityZones(); await _autoScalerWrapper.CreateGroupOfSize(3, _autoScalerWrapper.GroupName, zones); Console.WriteLine(new string('-', 80)); Console.WriteLine( "At this point, you have EC2 instances created. Once each instance starts, it listens for\n" + "HTTP requests. You can see these instances in the console or continue with the demo.\n"); Console.WriteLine(new string('-', 80)); Console.WriteLine("Press Enter when you're ready to continue."); if (interactive) Console.ReadLine(); Console.WriteLine("Creating variables that control the flow of the demo."); await _smParameterWrapper.Reset(); Console.WriteLine( "\nCreating an Elastic Load Balancing target group and load balancer. The target group\n" + "defines how the load balancer connects to instances. The load balancer provides a\n" + "single endpoint where clients connect and dispatches requests to instances in the group."); var defaultVpc = await _autoScalerWrapper.GetDefaultVpc(); var subnets = await _autoScalerWrapper.GetAllVpcSubnetsForZones(defaultVpc.VpcId, zones); var subnetIds = subnets.Select(s => s.SubnetId).ToList(); var targetGroup = await _elasticLoadBalancerWrapper.CreateTargetGroupOnVpc(_elasticLoadBalancerWrapper.TargetGroupName, protocol, port, defaultVpc.VpcId); await _elasticLoadBalancerWrapper.CreateLoadBalancerAndListener(_elasticLoadBalancerWrapper.LoadBalancerName, subnetIds, targetGroup); await _autoScalerWrapper.AttachLoadBalancerToGroup(_autoScalerWrapper.GroupName, targetGroup.TargetGroupArn); Console.WriteLine("\nVerifying access to the load balancer endpoint..."); var endPoint = await _elasticLoadBalancerWrapper.GetEndpointForLoadBalancerByName(_elasticLoadBalancerWrapper.LoadBalancerName); var loadBalancerAccess = await _elasticLoadBalancerWrapper.VerifyLoadBalancerEndpoint(endPoint); if (!loadBalancerAccess) { Console.WriteLine("\nCouldn't connect to the load balancer, verifying that the port is open..."); var ipString = await _httpClient.GetStringAsync("https://checkip.amazonaws.com"); ipString = ipString.Trim(); var defaultSecurityGroup = await _autoScalerWrapper.GetDefaultSecurityGroupForVpc(defaultVpc); var portIsOpen = _autoScalerWrapper.VerifyInboundPortForGroup(defaultSecurityGroup, port, ipString); var sshPortIsOpen = _autoScalerWrapper.VerifyInboundPortForGroup(defaultSecurityGroup, sshPort, ipString); if (!portIsOpen) { Console.WriteLine( "\nFor this example to work, the default security group for your default VPC must\n" + "allows access from this computer. You can either add it automatically from this\n" + "example or add it yourself using the AWS Management Console.\n"); if (!interactive || GetYesNoResponse( "Do you want to add a rule to the security group to allow inbound traffic from your computer's IP address?")) { await _autoScalerWrapper.OpenInboundPort(defaultSecurityGroup.GroupId, port, ipString); } } if (!sshPortIsOpen) { if (!interactive || GetYesNoResponse( "Do you want to add a rule to the security group to allow inbound SSH traffic for debugging from your computer's IP address?")) { await _autoScalerWrapper.OpenInboundPort(defaultSecurityGroup.GroupId, sshPort, ipString); } } loadBalancerAccess = await _elasticLoadBalancerWrapper.VerifyLoadBalancerEndpoint(endPoint); } if (loadBalancerAccess) { Console.WriteLine("Your load balancer is ready. You can access it by browsing to:"); Console.WriteLine($"\thttp://{endPoint}\n"); } else { Console.WriteLine( "\nCouldn't get a successful response from the load balancer endpoint. Troubleshoot by\n" + "manually verifying that your VPC and security group are configured correctly and that\n" + "you can successfully make a GET request to the load balancer endpoint:\n"); Console.WriteLine($"\thttp://{endPoint}\n"); } Console.WriteLine(new string('-', 80)); Console.WriteLine("Press Enter when you're ready to continue with the demo."); if (interactive) Console.ReadLine(); return true; } /// <summary> /// Demonstrate the steps of the scenario. /// </summary> /// <param name="interactive">True to run as an interactive scenario.</param> /// <returns>Async task.</returns> public static async Task<bool> Demo(bool interactive) { var ssmOnlyPolicy = Path.Join(_configuration["resourcePath"], "ssm_only_policy.json"); Console.WriteLine(new string('-', 80)); Console.WriteLine("Resetting parameters to starting values for demo."); await _smParameterWrapper.Reset(); Console.WriteLine("\nThis part of the demonstration shows how to toggle different parts of the system\n" + "to create situations where the web service fails, and shows how using a resilient\n" + "architecture can keep the web service running in spite of these failures."); Console.WriteLine(new string('-', 88)); Console.WriteLine("At the start, the load balancer endpoint returns recommendations and reports that all targets are healthy."); if (interactive) await DemoActionChoices(); Console.WriteLine($"The web service running on the EC2 instances gets recommendations by querying a DynamoDB table.\n" + $"The table name is contained in a Systems Manager parameter named '{_smParameterWrapper.TableParameter}'.\n" + $"To simulate a failure of the recommendation service, let's set this parameter to name a non-existent table.\n"); await _smParameterWrapper.PutParameterByName(_smParameterWrapper.TableParameter, "this-is-not-a-table"); Console.WriteLine("\nNow, sending a GET request to the load balancer endpoint returns a failure code. But, the service reports as\n" + "healthy to the load balancer because shallow health checks don't check for failure of the recommendation service."); if (interactive) await DemoActionChoices(); Console.WriteLine("Instead of failing when the recommendation service fails, the web service can return a static response."); Console.WriteLine("While this is not a perfect solution, it presents the customer with a somewhat better experience than failure."); await _smParameterWrapper.PutParameterByName(_smParameterWrapper.FailureResponseParameter, "static"); Console.WriteLine("\nNow, sending a GET request to the load balancer endpoint returns a static response."); Console.WriteLine("The service still reports as healthy because health checks are still shallow."); if (interactive) await DemoActionChoices(); Console.WriteLine("Let's reinstate the recommendation service.\n"); await _smParameterWrapper.PutParameterByName(_smParameterWrapper.TableParameter, _smParameterWrapper.TableName); Console.WriteLine( "\nLet's also substitute bad credentials for one of the instances in the target group so that it can't\n" + "access the DynamoDB recommendation table.\n" ); await _autoScalerWrapper.CreateInstanceProfileWithName( _autoScalerWrapper.BadCredsPolicyName, _autoScalerWrapper.BadCredsRoleName, _autoScalerWrapper.BadCredsProfileName, ssmOnlyPolicy, new List<string> { "AmazonSSMManagedInstanceCore" } ); var instances = await _autoScalerWrapper.GetInstancesByGroupName(_autoScalerWrapper.GroupName); var badInstanceId = instances.First(); var instanceProfile = await _autoScalerWrapper.GetInstanceProfile(badInstanceId); Console.WriteLine( $"Replacing the profile for instance {badInstanceId} with a profile that contains\n" + "bad credentials...\n" ); await _autoScalerWrapper.ReplaceInstanceProfile( badInstanceId, _autoScalerWrapper.BadCredsProfileName, instanceProfile.AssociationId ); Console.WriteLine( "Now, sending a GET request to the load balancer endpoint returns either a recommendation or a static response,\n" + "depending on which instance is selected by the load balancer.\n" ); if (interactive) await DemoActionChoices(); Console.WriteLine("\nLet's implement a deep health check. For this demo, a deep health check tests whether"); Console.WriteLine("the web service can access the DynamoDB table that it depends on for recommendations. Note that"); Console.WriteLine("the deep health check is only for ELB routing and not for Auto Scaling instance health."); Console.WriteLine("This kind of deep health check is not recommended for Auto Scaling instance health, because it"); Console.WriteLine("risks accidental termination of all instances in the Auto Scaling group when a dependent service fails."); Console.WriteLine("\nBy implementing deep health checks, the load balancer can detect when one of the instances is failing"); Console.WriteLine("and take that instance out of rotation."); await _smParameterWrapper.PutParameterByName(_smParameterWrapper.HealthCheckParameter, "deep"); Console.WriteLine($"\nNow, checking target health indicates that the instance with bad credentials ({badInstanceId})"); Console.WriteLine("is unhealthy. Note that it might take a minute or two for the load balancer to detect the unhealthy"); Console.WriteLine("instance. Sending a GET request to the load balancer endpoint always returns a recommendation, because"); Console.WriteLine("the load balancer takes unhealthy instances out of its rotation."); if (interactive) await DemoActionChoices(); Console.WriteLine("\nBecause the instances in this demo are controlled by an auto scaler, the simplest way to fix an unhealthy"); Console.WriteLine("instance is to terminate it and let the auto scaler start a new instance to replace it."); await _autoScalerWrapper.TryTerminateInstanceById(badInstanceId); Console.WriteLine($"\nEven while the instance is terminating and the new instance is starting, sending a GET"); Console.WriteLine("request to the web service continues to get a successful recommendation response because"); Console.WriteLine("starts and reports as healthy, it is included in the load balancing rotation."); Console.WriteLine("Note that terminating and replacing an instance typically takes several minutes, during which time you"); Console.WriteLine("can see the changing health check status until the new instance is running and healthy."); if (interactive) await DemoActionChoices(); Console.WriteLine("\nIf the recommendation service fails now, deep health checks mean all instances report as unhealthy."); await _smParameterWrapper.PutParameterByName(_smParameterWrapper.TableParameter, "this-is-not-a-table"); Console.WriteLine($"\nWhen all instances are unhealthy, the load balancer continues to route requests even to"); Console.WriteLine("unhealthy instances, allowing them to fail open and return a static response rather than fail"); Console.WriteLine("closed and report failure to the customer."); if (interactive) await DemoActionChoices(); await _smParameterWrapper.Reset(); Console.WriteLine(new string('-', 80)); return true; } /// <summary> /// Clean up the resources from the scenario. /// </summary> /// <param name="interactive">True to ask the user for cleanup.</param> /// <returns>Async task.</returns> public static async Task<bool> DestroyResources(bool interactive) { Console.WriteLine(new string('-', 80)); Console.WriteLine( "To keep things tidy and to avoid unwanted charges on your account, we can clean up all AWS resources\n" + "that were created for this demo." ); if (!interactive || GetYesNoResponse("Do you want to clean up all demo resources? (y/n) ")) { await _elasticLoadBalancerWrapper.DeleteLoadBalancerByName(_elasticLoadBalancerWrapper.LoadBalancerName); await _elasticLoadBalancerWrapper.DeleteTargetGroupByName(_elasticLoadBalancerWrapper.TargetGroupName); await _autoScalerWrapper.TerminateAndDeleteAutoScalingGroupWithName(_autoScalerWrapper.GroupName); await _autoScalerWrapper.DeleteKeyPairByName(_autoScalerWrapper.KeyPairName); await _autoScalerWrapper.DeleteTemplateByName(_autoScalerWrapper.LaunchTemplateName); await _autoScalerWrapper.DeleteInstanceProfile( _autoScalerWrapper.BadCredsProfileName, _autoScalerWrapper.BadCredsRoleName ); await _recommendations.DestroyDatabaseByName(_recommendations.TableName); } else { Console.WriteLine( "Ok, we'll leave the resources intact.\n" + "Don't forget to delete them when you're done with them or you might incur unexpected charges." ); } Console.WriteLine(new string('-', 80)); return true; }

创建一个包含自动扩缩和 Amazon EC2 操作的类。

/// <summary> /// Encapsulates Amazon EC2 Auto Scaling and EC2 management methods. /// </summary> public class AutoScalerWrapper { private readonly IAmazonAutoScaling _amazonAutoScaling; private readonly IAmazonEC2 _amazonEc2; private readonly IAmazonSimpleSystemsManagement _amazonSsm; private readonly IAmazonIdentityManagementService _amazonIam; private readonly string _instanceType = ""; private readonly string _amiParam = ""; private readonly string _launchTemplateName = ""; private readonly string _groupName = ""; private readonly string _instancePolicyName = ""; private readonly string _instanceRoleName = ""; private readonly string _instanceProfileName = ""; private readonly string _badCredsProfileName = ""; private readonly string _badCredsRoleName = ""; private readonly string _badCredsPolicyName = ""; private readonly string _keyPairName = ""; public string GroupName => _groupName; public string KeyPairName => _keyPairName; public string LaunchTemplateName => _launchTemplateName; public string InstancePolicyName => _instancePolicyName; public string BadCredsProfileName => _badCredsProfileName; public string BadCredsRoleName => _badCredsRoleName; public string BadCredsPolicyName => _badCredsPolicyName; /// <summary> /// Constructor for the AutoScalerWrapper. /// </summary> /// <param name="amazonAutoScaling">The injected AutoScaling client.</param> /// <param name="amazonEc2">The injected EC2 client.</param> /// <param name="amazonIam">The injected IAM client.</param> /// <param name="amazonSsm">The injected SSM client.</param> public AutoScalerWrapper( IAmazonAutoScaling amazonAutoScaling, IAmazonEC2 amazonEc2, IAmazonSimpleSystemsManagement amazonSsm, IAmazonIdentityManagementService amazonIam, IConfiguration configuration) { _amazonAutoScaling = amazonAutoScaling; _amazonEc2 = amazonEc2; _amazonSsm = amazonSsm; _amazonIam = amazonIam; var prefix = configuration["resourcePrefix"]; _instanceType = configuration["instanceType"]; _amiParam = configuration["amiParam"]; _launchTemplateName = prefix + "-template"; _groupName = prefix + "-group"; _instancePolicyName = prefix + "-pol"; _instanceRoleName = prefix + "-role"; _instanceProfileName = prefix + "-prof"; _badCredsPolicyName = prefix + "-bc-pol"; _badCredsRoleName = prefix + "-bc-role"; _badCredsProfileName = prefix + "-bc-prof"; _keyPairName = prefix + "-key-pair"; } /// <summary> /// Create a policy, role, and profile that is associated with instances with a specified name. /// An instance's associated profile defines a role that is assumed by the /// instance.The role has attached policies that specify the AWS permissions granted to /// clients that run on the instance. /// </summary> /// <param name="policyName">Name to use for the policy.</param> /// <param name="roleName">Name to use for the role.</param> /// <param name="profileName">Name to use for the profile.</param> /// <param name="ssmOnlyPolicyFile">Path to a policy file for SSM.</param> /// <param name="awsManagedPolicies">AWS Managed policies to be attached to the role.</param> /// <returns>The Arn of the profile.</returns> public async Task<string> CreateInstanceProfileWithName( string policyName, string roleName, string profileName, string ssmOnlyPolicyFile, List<string>? awsManagedPolicies = null) { var assumeRoleDoc = "{" + "\"Version\": \"2012-10-17\"," + "\"Statement\": [{" + "\"Effect\": \"Allow\"," + "\"Principal\": {" + "\"Service\": [" + "\"ec2.amazonaws.com\"" + "]" + "}," + "\"Action\": \"sts:AssumeRole\"" + "}]" + "}"; var policyDocument = await File.ReadAllTextAsync(ssmOnlyPolicyFile); var policyArn = ""; try { var createPolicyResult = await _amazonIam.CreatePolicyAsync( new CreatePolicyRequest { PolicyName = policyName, PolicyDocument = policyDocument }); policyArn = createPolicyResult.Policy.Arn; } catch (EntityAlreadyExistsException) { // The policy already exists, so we look it up to get the Arn. var policiesPaginator = _amazonIam.Paginators.ListPolicies( new ListPoliciesRequest() { Scope = PolicyScopeType.Local }); // Get the entire list using the paginator. await foreach (var policy in policiesPaginator.Policies) { if (policy.PolicyName.Equals(policyName)) { policyArn = policy.Arn; } } if (policyArn == null) { throw new InvalidOperationException("Policy not found"); } } try { await _amazonIam.CreateRoleAsync(new CreateRoleRequest() { RoleName = roleName, AssumeRolePolicyDocument = assumeRoleDoc, }); await _amazonIam.AttachRolePolicyAsync(new AttachRolePolicyRequest() { RoleName = roleName, PolicyArn = policyArn }); if (awsManagedPolicies != null) { foreach (var awsPolicy in awsManagedPolicies) { await _amazonIam.AttachRolePolicyAsync(new AttachRolePolicyRequest() { PolicyArn = $"arn:aws:iam::aws:policy/{awsPolicy}", RoleName = roleName }); } } } catch (EntityAlreadyExistsException) { Console.WriteLine("Role already exists."); } string profileArn = ""; try { var profileCreateResponse = await _amazonIam.CreateInstanceProfileAsync( new CreateInstanceProfileRequest() { InstanceProfileName = profileName }); // Allow time for the profile to be ready. profileArn = profileCreateResponse.InstanceProfile.Arn; Thread.Sleep(10000); await _amazonIam.AddRoleToInstanceProfileAsync( new AddRoleToInstanceProfileRequest() { InstanceProfileName = profileName, RoleName = roleName }); } catch (EntityAlreadyExistsException) { Console.WriteLine("Policy already exists."); var profileGetResponse = await _amazonIam.GetInstanceProfileAsync( new GetInstanceProfileRequest() { InstanceProfileName = profileName }); profileArn = profileGetResponse.InstanceProfile.Arn; } return profileArn; } /// <summary> /// Create a new key pair and save the file. /// </summary> /// <param name="newKeyPairName">The name of the new key pair.</param> /// <returns>Async task.</returns> public async Task CreateKeyPair(string newKeyPairName) { try { var keyResponse = await _amazonEc2.CreateKeyPairAsync( new CreateKeyPairRequest() { KeyName = newKeyPairName }); await File.WriteAllTextAsync($"{newKeyPairName}.pem", keyResponse.KeyPair.KeyMaterial); Console.WriteLine($"Created key pair {newKeyPairName}."); } catch (AlreadyExistsException) { Console.WriteLine("Key pair already exists."); } } /// <summary> /// Delete the key pair and file by name. /// </summary> /// <param name="deleteKeyPairName">The key pair to delete.</param> /// <returns>Async task.</returns> public async Task DeleteKeyPairByName(string deleteKeyPairName) { try { await _amazonEc2.DeleteKeyPairAsync( new DeleteKeyPairRequest() { KeyName = deleteKeyPairName }); File.Delete($"{deleteKeyPairName}.pem"); } catch (FileNotFoundException) { Console.WriteLine($"Key pair {deleteKeyPairName} not found."); } } /// <summary> /// Creates an Amazon EC2 launch template to use with Amazon EC2 Auto Scaling. /// The launch template specifies a Bash script in its user data field that runs after /// the instance is started. This script installs the Python packages and starts a Python /// web server on the instance. /// </summary> /// <param name="startupScriptPath">The path to a Bash script file that is run.</param> /// <param name="instancePolicyPath">The path to a permissions policy to create and attach to the profile.</param> /// <returns>The template object.</returns> public async Task<Amazon.EC2.Model.LaunchTemplate> CreateTemplate(string startupScriptPath, string instancePolicyPath) { await CreateKeyPair(_keyPairName); await CreateInstanceProfileWithName(_instancePolicyName, _instanceRoleName, _instanceProfileName, instancePolicyPath); var startServerText = await File.ReadAllTextAsync(startupScriptPath); var plainTextBytes = System.Text.Encoding.UTF8.GetBytes(startServerText); var amiLatest = await _amazonSsm.GetParameterAsync( new GetParameterRequest() { Name = _amiParam }); var amiId = amiLatest.Parameter.Value; var launchTemplateResponse = await _amazonEc2.CreateLaunchTemplateAsync( new CreateLaunchTemplateRequest() { LaunchTemplateName = _launchTemplateName, LaunchTemplateData = new RequestLaunchTemplateData() { InstanceType = _instanceType, ImageId = amiId, IamInstanceProfile = new LaunchTemplateIamInstanceProfileSpecificationRequest() { Name = _instanceProfileName }, KeyName = _keyPairName, UserData = System.Convert.ToBase64String(plainTextBytes) } }); return launchTemplateResponse.LaunchTemplate; } /// <summary> /// Get a list of Availability Zones in the AWS Region of the Amazon EC2 Client. /// </summary> /// <returns>A list of availability zones.</returns> public async Task<List<string>> DescribeAvailabilityZones() { var zoneResponse = await _amazonEc2.DescribeAvailabilityZonesAsync( new DescribeAvailabilityZonesRequest()); return zoneResponse.AvailabilityZones.Select(z => z.ZoneName).ToList(); } /// <summary> /// Create an EC2 Auto Scaling group of a specified size and name. /// </summary> /// <param name="groupSize">The size for the group.</param> /// <param name="groupName">The name for the group.</param> /// <param name="availabilityZones">The availability zones for the group.</param> /// <returns>Async task.</returns> public async Task CreateGroupOfSize(int groupSize, string groupName, List<string> availabilityZones) { try { await _amazonAutoScaling.CreateAutoScalingGroupAsync( new CreateAutoScalingGroupRequest() { AutoScalingGroupName = groupName, AvailabilityZones = availabilityZones, LaunchTemplate = new Amazon.AutoScaling.Model.LaunchTemplateSpecification() { LaunchTemplateName = _launchTemplateName, Version = "$Default" }, MaxSize = groupSize, MinSize = groupSize }); Console.WriteLine($"Created EC2 Auto Scaling group {groupName} with size {groupSize}."); } catch (EntityAlreadyExistsException) { Console.WriteLine($"EC2 Auto Scaling group {groupName} already exists."); } } /// <summary> /// Get the default VPC for the account. /// </summary> /// <returns>The default VPC object.</returns> public async Task<Vpc> GetDefaultVpc() { var vpcResponse = await _amazonEc2.DescribeVpcsAsync( new DescribeVpcsRequest() { Filters = new List<Amazon.EC2.Model.Filter>() { new ("is-default", new List<string>() { "true" }) } }); return vpcResponse.Vpcs[0]; } /// <summary> /// Get all the subnets for a Vpc in a set of availability zones. /// </summary> /// <param name="vpcId">The Id of the Vpc.</param> /// <param name="availabilityZones">The list of availability zones.</param> /// <returns>The collection of subnet objects.</returns> public async Task<List<Subnet>> GetAllVpcSubnetsForZones(string vpcId, List<string> availabilityZones) { var subnets = new List<Subnet>(); var subnetPaginator = _amazonEc2.Paginators.DescribeSubnets( new DescribeSubnetsRequest() { Filters = new List<Amazon.EC2.Model.Filter>() { new ("vpc-id", new List<string>() { vpcId}), new ("availability-zone", availabilityZones), new ("default-for-az", new List<string>() { "true" }) } }); // Get the entire list using the paginator. await foreach (var subnet in subnetPaginator.Subnets) { subnets.Add(subnet); } return subnets; } /// <summary> /// Delete a launch template by name. /// </summary> /// <param name="templateName">The name of the template to delete.</param> /// <returns>Async task.</returns> public async Task DeleteTemplateByName(string templateName) { try { await _amazonEc2.DeleteLaunchTemplateAsync( new DeleteLaunchTemplateRequest() { LaunchTemplateName = templateName }); } catch (AmazonClientException) { Console.WriteLine($"Unable to delete template {templateName}."); } } /// <summary> /// Detaches a role from an instance profile, detaches policies from the role, /// and deletes all the resources. /// </summary> /// <param name="profileName">The name of the profile to delete.</param> /// <param name="roleName">The name of the role to delete.</param> /// <returns>Async task.</returns> public async Task DeleteInstanceProfile(string profileName, string roleName) { try { await _amazonIam.RemoveRoleFromInstanceProfileAsync( new RemoveRoleFromInstanceProfileRequest() { InstanceProfileName = profileName, RoleName = roleName }); await _amazonIam.DeleteInstanceProfileAsync( new DeleteInstanceProfileRequest() { InstanceProfileName = profileName }); var attachedPolicies = await _amazonIam.ListAttachedRolePoliciesAsync( new ListAttachedRolePoliciesRequest() { RoleName = roleName }); foreach (var policy in attachedPolicies.AttachedPolicies) { await _amazonIam.DetachRolePolicyAsync( new DetachRolePolicyRequest() { RoleName = roleName, PolicyArn = policy.PolicyArn }); // Delete the custom policies only. if (!policy.PolicyArn.StartsWith("arn:aws:iam::aws")) { await _amazonIam.DeletePolicyAsync( new Amazon.IdentityManagement.Model.DeletePolicyRequest() { PolicyArn = policy.PolicyArn }); } } await _amazonIam.DeleteRoleAsync( new DeleteRoleRequest() { RoleName = roleName }); } catch (NoSuchEntityException) { Console.WriteLine($"Instance profile {profileName} does not exist."); } } /// <summary> /// Gets data about the instances in an EC2 Auto Scaling group by its group name. /// </summary> /// <param name="group">The name of the auto scaling group.</param> /// <returns>A collection of instance Ids.</returns> public async Task<IEnumerable<string>> GetInstancesByGroupName(string group) { var instanceResponse = await _amazonAutoScaling.DescribeAutoScalingGroupsAsync( new DescribeAutoScalingGroupsRequest() { AutoScalingGroupNames = new List<string>() { group } }); var instanceIds = instanceResponse.AutoScalingGroups.SelectMany( g => g.Instances.Select(i => i.InstanceId)); return instanceIds; } /// <summary> /// Get the instance profile association data for an instance. /// </summary> /// <param name="instanceId">The Id of the instance.</param> /// <returns>Instance profile associations data.</returns> public async Task<IamInstanceProfileAssociation> GetInstanceProfile(string instanceId) { var response = await _amazonEc2.DescribeIamInstanceProfileAssociationsAsync( new DescribeIamInstanceProfileAssociationsRequest() { Filters = new List<Amazon.EC2.Model.Filter>() { new ("instance-id", new List<string>() { instanceId }) }, }); return response.IamInstanceProfileAssociations[0]; } /// <summary> /// Replace the profile associated with a running instance. After the profile is replaced, the instance /// is rebooted to ensure that it uses the new profile. When the instance is ready, Systems Manager is /// used to restart the Python web server. /// </summary> /// <param name="instanceId">The Id of the instance to update.</param> /// <param name="credsProfileName">The name of the new profile to associate with the specified instance.</param> /// <param name="associationId">The Id of the existing profile association for the instance.</param> /// <returns>Async task.</returns> public async Task ReplaceInstanceProfile(string instanceId, string credsProfileName, string associationId) { await _amazonEc2.ReplaceIamInstanceProfileAssociationAsync( new ReplaceIamInstanceProfileAssociationRequest() { AssociationId = associationId, IamInstanceProfile = new IamInstanceProfileSpecification() { Name = credsProfileName } }); // Allow time before resetting. Thread.Sleep(25000); var instanceReady = false; var retries = 5; while (retries-- > 0 && !instanceReady) { await _amazonEc2.RebootInstancesAsync( new RebootInstancesRequest(new List<string>() { instanceId })); Thread.Sleep(10000); var instancesPaginator = _amazonSsm.Paginators.DescribeInstanceInformation( new DescribeInstanceInformationRequest()); // Get the entire list using the paginator. await foreach (var instance in instancesPaginator.InstanceInformationList) { instanceReady = instance.InstanceId == instanceId; if (instanceReady) { break; } } } Console.WriteLine($"Sending restart command to instance {instanceId}"); await _amazonSsm.SendCommandAsync( new SendCommandRequest() { InstanceIds = new List<string>() { instanceId }, DocumentName = "AWS-RunShellScript", Parameters = new Dictionary<string, List<string>>() { {"commands", new List<string>() { "cd / && sudo python3 server.py 80" }} } }); Console.WriteLine($"Restarted the web server on instance {instanceId}"); } /// <summary> /// Try to terminate an instance by its Id. /// </summary> /// <param name="instanceId">The Id of the instance to terminate.</param> /// <returns>Async task.</returns> public async Task TryTerminateInstanceById(string instanceId) { var stopping = false; Console.WriteLine($"Stopping {instanceId}..."); while (!stopping) { try { await _amazonAutoScaling.TerminateInstanceInAutoScalingGroupAsync( new TerminateInstanceInAutoScalingGroupRequest() { InstanceId = instanceId, ShouldDecrementDesiredCapacity = false }); stopping = true; } catch (ScalingActivityInProgressException) { Console.WriteLine($"Scaling activity in progress for {instanceId}. Waiting..."); Thread.Sleep(10000); } } } /// <summary> /// Tries to delete the EC2 Auto Scaling group. If the group is in use or in progress, /// waits and retries until the group is successfully deleted. /// </summary> /// <param name="groupName">The name of the group to try to delete.</param> /// <returns>Async task.</returns> public async Task TryDeleteGroupByName(string groupName) { var stopped = false; while (!stopped) { try { await _amazonAutoScaling.DeleteAutoScalingGroupAsync( new DeleteAutoScalingGroupRequest() { AutoScalingGroupName = groupName }); stopped = true; } catch (Exception e) when ((e is ScalingActivityInProgressException) || (e is Amazon.AutoScaling.Model.ResourceInUseException)) { Console.WriteLine($"Some instances are still running. Waiting..."); Thread.Sleep(10000); } } } /// <summary> /// Terminate instances and delete the Auto Scaling group by name. /// </summary> /// <param name="groupName">The name of the group to delete.</param> /// <returns>Async task.</returns> public async Task TerminateAndDeleteAutoScalingGroupWithName(string groupName) { var describeGroupsResponse = await _amazonAutoScaling.DescribeAutoScalingGroupsAsync( new DescribeAutoScalingGroupsRequest() { AutoScalingGroupNames = new List<string>() { groupName } }); if (describeGroupsResponse.AutoScalingGroups.Any()) { // Update the size to 0. await _amazonAutoScaling.UpdateAutoScalingGroupAsync( new UpdateAutoScalingGroupRequest() { AutoScalingGroupName = groupName, MinSize = 0 }); var group = describeGroupsResponse.AutoScalingGroups[0]; foreach (var instance in group.Instances) { await TryTerminateInstanceById(instance.InstanceId); } await TryDeleteGroupByName(groupName); } else { Console.WriteLine($"No groups found with name {groupName}."); } } /// <summary> /// Get the default security group for a specified Vpc. /// </summary> /// <param name="vpc">The Vpc to search.</param> /// <returns>The default security group.</returns> public async Task<SecurityGroup> GetDefaultSecurityGroupForVpc(Vpc vpc) { var groupResponse = await _amazonEc2.DescribeSecurityGroupsAsync( new DescribeSecurityGroupsRequest() { Filters = new List<Amazon.EC2.Model.Filter>() { new ("group-name", new List<string>() { "default" }), new ("vpc-id", new List<string>() { vpc.VpcId }) } }); return groupResponse.SecurityGroups[0]; } /// <summary> /// Verify the default security group of a Vpc allows ingress from the calling computer. /// This can be done by allowing ingress from this computer's IP address. /// In some situations, such as connecting from a corporate network, you must instead specify /// a prefix list Id. You can also temporarily open the port to any IP address while running this example. /// If you do, be sure to remove public access when you're done. /// </summary> /// <param name="vpc">The group to check.</param> /// <param name="port">The port to verify.</param> /// <param name="ipAddress">This computer's IP address.</param> /// <returns>True if the ip address is allowed on the group.</returns> public bool VerifyInboundPortForGroup(SecurityGroup group, int port, string ipAddress) { var portIsOpen = false; foreach (var ipPermission in group.IpPermissions) { if (ipPermission.FromPort == port) { foreach (var ipRange in ipPermission.Ipv4Ranges) { var cidr = ipRange.CidrIp; if (cidr.StartsWith(ipAddress) || cidr == "0.0.0.0/0") { portIsOpen = true; } } if (ipPermission.PrefixListIds.Any()) { portIsOpen = true; } if (!portIsOpen) { Console.WriteLine("The inbound rule does not appear to be open to either this computer's IP\n" + "address, to all IP addresses (0.0.0.0/0), or to a prefix list ID."); } else { break; } } } return portIsOpen; } /// <summary> /// Add an ingress rule to the specified security group that allows access on the /// specified port from the specified IP address. /// </summary> /// <param name="groupId">The Id of the security group to modify.</param> /// <param name="port">The port to open.</param> /// <param name="ipAddress">The IP address to allow access.</param> /// <returns>Async task.</returns> public async Task OpenInboundPort(string groupId, int port, string ipAddress) { await _amazonEc2.AuthorizeSecurityGroupIngressAsync( new AuthorizeSecurityGroupIngressRequest() { GroupId = groupId, IpPermissions = new List<IpPermission>() { new IpPermission() { FromPort = port, ToPort = port, IpProtocol = "tcp", Ipv4Ranges = new List<IpRange>() { new IpRange() { CidrIp = $"{ipAddress}/32" } } } } }); } /// <summary> /// Attaches an Elastic Load Balancing (ELB) target group to this EC2 Auto Scaling group. /// The /// </summary> /// <param name="autoScalingGroupName">The name of the Auto Scaling group.</param> /// <param name="targetGroupArn">The Arn for the target group.</param> /// <returns>Async task.</returns> public async Task AttachLoadBalancerToGroup(string autoScalingGroupName, string targetGroupArn) { await _amazonAutoScaling.AttachLoadBalancerTargetGroupsAsync( new AttachLoadBalancerTargetGroupsRequest() { AutoScalingGroupName = autoScalingGroupName, TargetGroupARNs = new List<string>() { targetGroupArn } }); } }

创建一个包含弹性负载均衡操作的类。

/// <summary> /// Encapsulates Elastic Load Balancer actions. /// </summary> public class ElasticLoadBalancerWrapper { private readonly IAmazonElasticLoadBalancingV2 _amazonElasticLoadBalancingV2; private string? _endpoint = null; private readonly string _targetGroupName = ""; private readonly string _loadBalancerName = ""; HttpClient _httpClient = new(); public string TargetGroupName => _targetGroupName; public string LoadBalancerName => _loadBalancerName; /// <summary> /// Constructor for the Elastic Load Balancer wrapper. /// </summary> /// <param name="amazonElasticLoadBalancingV2">The injected load balancing v2 client.</param> /// <param name="configuration">The injected configuration.</param> public ElasticLoadBalancerWrapper( IAmazonElasticLoadBalancingV2 amazonElasticLoadBalancingV2, IConfiguration configuration) { _amazonElasticLoadBalancingV2 = amazonElasticLoadBalancingV2; var prefix = configuration["resourcePrefix"]; _targetGroupName = prefix + "-tg"; _loadBalancerName = prefix + "-lb"; } /// <summary> /// Get the HTTP Endpoint of a load balancer by its name. /// </summary> /// <param name="loadBalancerName">The name of the load balancer.</param> /// <returns>The HTTP endpoint.</returns> public async Task<string> GetEndpointForLoadBalancerByName(string loadBalancerName) { if (_endpoint == null) { var endpointResponse = await _amazonElasticLoadBalancingV2.DescribeLoadBalancersAsync( new DescribeLoadBalancersRequest() { Names = new List<string>() { loadBalancerName } }); _endpoint = endpointResponse.LoadBalancers[0].DNSName; } return _endpoint; } /// <summary> /// Return the GET response for an endpoint as text. /// </summary> /// <param name="endpoint">The endpoint for the request.</param> /// <returns>The request response.</returns> public async Task<string> GetEndPointResponse(string endpoint) { var endpointResponse = await _httpClient.GetAsync($"http://{endpoint}"); var textResponse = await endpointResponse.Content.ReadAsStringAsync(); return textResponse!; } /// <summary> /// Get the target health for a group by name. /// </summary> /// <param name="groupName">The name of the group.</param> /// <returns>The collection of health descriptions.</returns> public async Task<List<TargetHealthDescription>> CheckTargetHealthForGroup(string groupName) { List<TargetHealthDescription> result = null!; try { var groupResponse = await _amazonElasticLoadBalancingV2.DescribeTargetGroupsAsync( new DescribeTargetGroupsRequest() { Names = new List<string>() { groupName } }); var healthResponse = await _amazonElasticLoadBalancingV2.DescribeTargetHealthAsync( new DescribeTargetHealthRequest() { TargetGroupArn = groupResponse.TargetGroups[0].TargetGroupArn }); ; result = healthResponse.TargetHealthDescriptions; } catch (TargetGroupNotFoundException) { Console.WriteLine($"Target group {groupName} not found."); } return result; } /// <summary> /// Create an Elastic Load Balancing target group. The target group specifies how the load balancer forwards /// requests to instances in the group and how instance health is checked. /// /// To speed up this demo, the health check is configured with shortened times and lower thresholds. In production, /// you might want to decrease the sensitivity of your health checks to avoid unwanted failures. /// </summary> /// <param name="groupName">The name for the group.</param> /// <param name="protocol">The protocol, such as HTTP.</param> /// <param name="port">The port to use to forward requests, such as 80.</param> /// <param name="vpcId">The Id of the Vpc in which the load balancer exists.</param> /// <returns>The new TargetGroup object.</returns> public async Task<TargetGroup> CreateTargetGroupOnVpc(string groupName, ProtocolEnum protocol, int port, string vpcId) { var createResponse = await _amazonElasticLoadBalancingV2.CreateTargetGroupAsync( new CreateTargetGroupRequest() { Name = groupName, Protocol = protocol, Port = port, HealthCheckPath = "/healthcheck", HealthCheckIntervalSeconds = 10, HealthCheckTimeoutSeconds = 5, HealthyThresholdCount = 2, UnhealthyThresholdCount = 2, VpcId = vpcId }); var targetGroup = createResponse.TargetGroups[0]; return targetGroup; } /// <summary> /// Create an Elastic Load Balancing load balancer that uses the specified subnets /// and forwards requests to the specified target group. /// </summary> /// <param name="name">The name for the new load balancer.</param> /// <param name="subnetIds">Subnets for the load balancer.</param> /// <param name="targetGroup">Target group for forwarded requests.</param> /// <returns>The new LoadBalancer object.</returns> public async Task<LoadBalancer> CreateLoadBalancerAndListener(string name, List<string> subnetIds, TargetGroup targetGroup) { var createLbResponse = await _amazonElasticLoadBalancingV2.CreateLoadBalancerAsync( new CreateLoadBalancerRequest() { Name = name, Subnets = subnetIds }); var loadBalancerArn = createLbResponse.LoadBalancers[0].LoadBalancerArn; // Wait for load balancer to be available. var loadBalancerReady = false; while (!loadBalancerReady) { try { var describeResponse = await _amazonElasticLoadBalancingV2.DescribeLoadBalancersAsync( new DescribeLoadBalancersRequest() { Names = new List<string>() { name } }); var loadBalancerState = describeResponse.LoadBalancers[0].State.Code; loadBalancerReady = loadBalancerState == LoadBalancerStateEnum.Active; } catch (LoadBalancerNotFoundException) { loadBalancerReady = false; } Thread.Sleep(10000); } // Create the listener. await _amazonElasticLoadBalancingV2.CreateListenerAsync( new CreateListenerRequest() { LoadBalancerArn = loadBalancerArn, Protocol = targetGroup.Protocol, Port = targetGroup.Port, DefaultActions = new List<Action>() { new Action() { Type = ActionTypeEnum.Forward, TargetGroupArn = targetGroup.TargetGroupArn } } }); return createLbResponse.LoadBalancers[0]; } /// <summary> /// Verify this computer can successfully send a GET request to the /// load balancer endpoint. /// </summary> /// <param name="endpoint">The endpoint to check.</param> /// <returns>True if successful.</returns> public async Task<bool> VerifyLoadBalancerEndpoint(string endpoint) { var success = false; var retries = 3; while (!success && retries > 0) { try { var endpointResponse = await _httpClient.GetAsync($"http://{endpoint}"); Console.WriteLine($"Response: {endpointResponse.StatusCode}."); if (endpointResponse.IsSuccessStatusCode) { success = true; } else { retries = 0; } } catch (HttpRequestException) { Console.WriteLine("Connection error, retrying..."); retries--; Thread.Sleep(10000); } } return success; } /// <summary> /// Delete a load balancer by its specified name. /// </summary> /// <param name="name">The name of the load balancer to delete.</param> /// <returns>Async task.</returns> public async Task DeleteLoadBalancerByName(string name) { try { var describeLoadBalancerResponse = await _amazonElasticLoadBalancingV2.DescribeLoadBalancersAsync( new DescribeLoadBalancersRequest() { Names = new List<string>() { name } }); var lbArn = describeLoadBalancerResponse.LoadBalancers[0].LoadBalancerArn; await _amazonElasticLoadBalancingV2.DeleteLoadBalancerAsync( new DeleteLoadBalancerRequest() { LoadBalancerArn = lbArn } ); } catch (LoadBalancerNotFoundException) { Console.WriteLine($"Load balancer {name} not found."); } } /// <summary> /// Delete a TargetGroup by its specified name. /// </summary> /// <param name="groupName">Name of the group to delete.</param> /// <returns>Async task.</returns> public async Task DeleteTargetGroupByName(string groupName) { var done = false; while (!done) { try { var groupResponse = await _amazonElasticLoadBalancingV2.DescribeTargetGroupsAsync( new DescribeTargetGroupsRequest() { Names = new List<string>() { groupName } }); var targetArn = groupResponse.TargetGroups[0].TargetGroupArn; await _amazonElasticLoadBalancingV2.DeleteTargetGroupAsync( new DeleteTargetGroupRequest() { TargetGroupArn = targetArn }); Console.WriteLine($"Deleted load balancing target group {groupName}."); done = true; } catch (TargetGroupNotFoundException) { Console.WriteLine( $"Target group {groupName} not found, could not delete."); done = true; } catch (ResourceInUseException) { Console.WriteLine("Target group not yet released, waiting..."); Thread.Sleep(10000); } } } }

创建一个使用 DynamoDB 模拟推荐服务的类。

/// <summary> /// Encapsulates a DynamoDB table to use as a service that recommends books, movies, and songs. /// </summary> public class Recommendations { private readonly IAmazonDynamoDB _amazonDynamoDb; private readonly DynamoDBContext _context; private readonly string _tableName; public string TableName => _tableName; /// <summary> /// Constructor for the Recommendations service. /// </summary> /// <param name="amazonDynamoDb">The injected DynamoDb client.</param> /// <param name="configuration">The injected configuration.</param> public Recommendations(IAmazonDynamoDB amazonDynamoDb, IConfiguration configuration) { _amazonDynamoDb = amazonDynamoDb; _context = new DynamoDBContext(_amazonDynamoDb); _tableName = configuration["databaseName"]!; } /// <summary> /// Create the DynamoDb table with a specified name. /// </summary> /// <param name="tableName">The name for the table.</param> /// <returns>True when ready.</returns> public async Task<bool> CreateDatabaseWithName(string tableName) { try { Console.Write($"Creating table {tableName}..."); var createRequest = new CreateTableRequest() { TableName = tableName, AttributeDefinitions = new List<AttributeDefinition>() { new AttributeDefinition() { AttributeName = "MediaType", AttributeType = ScalarAttributeType.S }, new AttributeDefinition() { AttributeName = "ItemId", AttributeType = ScalarAttributeType.N } }, KeySchema = new List<KeySchemaElement>() { new KeySchemaElement() { AttributeName = "MediaType", KeyType = KeyType.HASH }, new KeySchemaElement() { AttributeName = "ItemId", KeyType = KeyType.RANGE } }, ProvisionedThroughput = new ProvisionedThroughput() { ReadCapacityUnits = 5, WriteCapacityUnits = 5 } }; await _amazonDynamoDb.CreateTableAsync(createRequest); // Wait until the table is ACTIVE and then report success. Console.Write("\nWaiting for table to become active..."); var request = new DescribeTableRequest { TableName = tableName }; TableStatus status; do { Thread.Sleep(2000); var describeTableResponse = await _amazonDynamoDb.DescribeTableAsync(request); status = describeTableResponse.Table.TableStatus; Console.Write("."); } while (status != "ACTIVE"); return status == TableStatus.ACTIVE; } catch (ResourceInUseException) { Console.WriteLine($"Table {tableName} already exists."); return false; } } /// <summary> /// Populate the database table with data from a specified path. /// </summary> /// <param name="databaseTableName">The name of the table.</param> /// <param name="recommendationsPath">The path of the recommendations data.</param> /// <returns>Async task.</returns> public async Task PopulateDatabase(string databaseTableName, string recommendationsPath) { var recommendationsText = await File.ReadAllTextAsync(recommendationsPath); var records = JsonSerializer.Deserialize<RecommendationModel[]>(recommendationsText); var batchWrite = _context.CreateBatchWrite<RecommendationModel>(); foreach (var record in records!) { batchWrite.AddPutItem(record); } await batchWrite.ExecuteAsync(); } /// <summary> /// Delete the recommendation table by name. /// </summary> /// <param name="tableName">The name of the recommendation table.</param> /// <returns>Async task.</returns> public async Task DestroyDatabaseByName(string tableName) { try { await _amazonDynamoDb.DeleteTableAsync( new DeleteTableRequest() { TableName = tableName }); Console.WriteLine($"Table {tableName} was deleted."); } catch (ResourceNotFoundException) { Console.WriteLine($"Table {tableName} not found"); } } }

创建一个包含 Systems Manager 操作的类。

/// <summary> /// Encapsulates Systems Manager parameter operations. This example uses these parameters /// to drive the demonstration of resilient architecture, such as failure of a dependency or /// how the service responds to a health check. /// </summary> public class SmParameterWrapper { private readonly IAmazonSimpleSystemsManagement _amazonSimpleSystemsManagement; private readonly string _tableParameter = "doc-example-resilient-architecture-table"; private readonly string _failureResponseParameter = "doc-example-resilient-architecture-failure-response"; private readonly string _healthCheckParameter = "doc-example-resilient-architecture-health-check"; private readonly string _tableName = ""; public string TableParameter => _tableParameter; public string TableName => _tableName; public string HealthCheckParameter => _healthCheckParameter; public string FailureResponseParameter => _failureResponseParameter; /// <summary> /// Constructor for the SmParameterWrapper. /// </summary> /// <param name="amazonSimpleSystemsManagement">The injected Simple Systems Management client.</param> /// <param name="configuration">The injected configuration.</param> public SmParameterWrapper(IAmazonSimpleSystemsManagement amazonSimpleSystemsManagement, IConfiguration configuration) { _amazonSimpleSystemsManagement = amazonSimpleSystemsManagement; _tableName = configuration["databaseName"]!; } /// <summary> /// Reset the Systems Manager parameters to starting values for the demo. /// </summary> /// <returns>Async task.</returns> public async Task Reset() { await this.PutParameterByName(_tableParameter, _tableName); await this.PutParameterByName(_failureResponseParameter, "none"); await this.PutParameterByName(_healthCheckParameter, "shallow"); } /// <summary> /// Set the value of a named Systems Manager parameter. /// </summary> /// <param name="name">The name of the parameter.</param> /// <param name="value">The value to set.</param> /// <returns>Async task.</returns> public async Task PutParameterByName(string name, string value) { await _amazonSimpleSystemsManagement.PutParameterAsync( new PutParameterRequest() { Name = name, Value = value, Overwrite = true }); } }

以下代码示例演示了操作流程:

  • 创建组并向其授予完整的 Amazon S3 访问权限。

  • 创建无权访问 Amazon S3 的新用户。

  • 将用户添加到组并显示他们现在拥有的 Amazon S3 权限,然后清除资源。

Amazon SDK for .NET
注意

还有更多相关信息 GitHub。在 Amazon 代码示例存储库中查找完整示例,了解如何进行设置和运行。

global using Amazon.IdentityManagement; global using Amazon.S3; global using Amazon.SecurityToken; global using IAMActions; global using IamScenariosCommon; global using Microsoft.Extensions.DependencyInjection; global using Microsoft.Extensions.Hosting; global using Microsoft.Extensions.Logging; global using Microsoft.Extensions.Logging.Console; global using Microsoft.Extensions.Logging.Debug; namespace IAMActions; public class IAMWrapper { private readonly IAmazonIdentityManagementService _IAMService; /// <summary> /// Constructor for the IAMWrapper class. /// </summary> /// <param name="IAMService">An IAM client object.</param> public IAMWrapper(IAmazonIdentityManagementService IAMService) { _IAMService = IAMService; } /// <summary> /// Add an existing IAM user to an existing IAM group. /// </summary> /// <param name="userName">The username of the user to add.</param> /// <param name="groupName">The name of the group to add the user to.</param> /// <returns>A Boolean value indicating the success of the action.</returns> public async Task<bool> AddUserToGroupAsync(string userName, string groupName) { var response = await _IAMService.AddUserToGroupAsync(new AddUserToGroupRequest { GroupName = groupName, UserName = userName, }); return response.HttpStatusCode == HttpStatusCode.OK; } /// <summary> /// Attach an IAM policy to a role. /// </summary> /// <param name="policyArn">The policy to attach.</param> /// <param name="roleName">The role that the policy will be attached to.</param> /// <returns>A Boolean value indicating the success of the action.</returns> public async Task<bool> AttachRolePolicyAsync(string policyArn, string roleName) { var response = await _IAMService.AttachRolePolicyAsync(new AttachRolePolicyRequest { PolicyArn = policyArn, RoleName = roleName, }); return response.HttpStatusCode == System.Net.HttpStatusCode.OK; } /// <summary> /// Create an IAM access key for a user. /// </summary> /// <param name="userName">The username for which to create the IAM access /// key.</param> /// <returns>The AccessKey.</returns> public async Task<AccessKey> CreateAccessKeyAsync(string userName) { var response = await _IAMService.CreateAccessKeyAsync(new CreateAccessKeyRequest { UserName = userName, }); return response.AccessKey; } /// <summary> /// Create an IAM group. /// </summary> /// <param name="groupName">The name to give the IAM group.</param> /// <returns>The IAM group that was created.</returns> public async Task<Group> CreateGroupAsync(string groupName) { var response = await _IAMService.CreateGroupAsync(new CreateGroupRequest { GroupName = groupName }); return response.Group; } /// <summary> /// Create an IAM policy. /// </summary> /// <param name="policyName">The name to give the new IAM policy.</param> /// <param name="policyDocument">The policy document for the new policy.</param> /// <returns>The new IAM policy object.</returns> public async Task<ManagedPolicy> CreatePolicyAsync(string policyName, string policyDocument) { var response = await _IAMService.CreatePolicyAsync(new CreatePolicyRequest { PolicyDocument = policyDocument, PolicyName = policyName, }); return response.Policy; } /// <summary> /// Create a new IAM role. /// </summary> /// <param name="roleName">The name of the IAM role.</param> /// <param name="rolePolicyDocument">The name of the IAM policy document /// for the new role.</param> /// <returns>The Amazon Resource Name (ARN) of the role.</returns> public async Task<string> CreateRoleAsync(string roleName, string rolePolicyDocument) { var request = new CreateRoleRequest { RoleName = roleName, AssumeRolePolicyDocument = rolePolicyDocument, }; var response = await _IAMService.CreateRoleAsync(request); return response.Role.Arn; } /// <summary> /// Create an IAM service-linked role. /// </summary> /// <param name="serviceName">The name of the AWS Service.</param> /// <param name="description">A description of the IAM service-linked role.</param> /// <returns>The IAM role that was created.</returns> public async Task<Role> CreateServiceLinkedRoleAsync(string serviceName, string description) { var request = new CreateServiceLinkedRoleRequest { AWSServiceName = serviceName, Description = description }; var response = await _IAMService.CreateServiceLinkedRoleAsync(request); return response.Role; } /// <summary> /// Create an IAM user. /// </summary> /// <param name="userName">The username for the new IAM user.</param> /// <returns>The IAM user that was created.</returns> public async Task<User> CreateUserAsync(string userName) { var response = await _IAMService.CreateUserAsync(new CreateUserRequest { UserName = userName }); return response.User; } /// <summary> /// Delete an IAM user's access key. /// </summary> /// <param name="accessKeyId">The Id for the IAM access key.</param> /// <param name="userName">The username of the user that owns the IAM /// access key.</param> /// <returns>A Boolean value indicating the success of the action.</returns> public async Task<bool> DeleteAccessKeyAsync(string accessKeyId, string userName) { var response = await _IAMService.DeleteAccessKeyAsync(new DeleteAccessKeyRequest { AccessKeyId = accessKeyId, UserName = userName, }); return response.HttpStatusCode == System.Net.HttpStatusCode.OK; } /// <summary> /// Delete an IAM group. /// </summary> /// <param name="groupName">The name of the IAM group to delete.</param> /// <returns>A Boolean value indicating the success of the action.</returns> public async Task<bool> DeleteGroupAsync(string groupName) { var response = await _IAMService.DeleteGroupAsync(new DeleteGroupRequest { GroupName = groupName }); return response.HttpStatusCode == HttpStatusCode.OK; } /// <summary> /// Delete an IAM policy associated with an IAM group. /// </summary> /// <param name="groupName">The name of the IAM group associated with the /// policy.</param> /// <param name="policyName">The name of the policy to delete.</param> /// <returns>A Boolean value indicating the success of the action.</returns> public async Task<bool> DeleteGroupPolicyAsync(string groupName, string policyName) { var request = new DeleteGroupPolicyRequest() { GroupName = groupName, PolicyName = policyName, }; var response = await _IAMService.DeleteGroupPolicyAsync(request); return response.HttpStatusCode == System.Net.HttpStatusCode.OK; } /// <summary> /// Delete an IAM policy. /// </summary> /// <param name="policyArn">The Amazon Resource Name (ARN) of the policy to /// delete.</param> /// <returns>A Boolean value indicating the success of the action.</returns> public async Task<bool> DeletePolicyAsync(string policyArn) { var response = await _IAMService.DeletePolicyAsync(new DeletePolicyRequest { PolicyArn = policyArn }); return response.HttpStatusCode == System.Net.HttpStatusCode.OK; } /// <summary> /// Delete an IAM role. /// </summary> /// <param name="roleName">The name of the IAM role to delete.</param> /// <returns>A Boolean value indicating the success of the action.</returns> public async Task<bool> DeleteRoleAsync(string roleName) { var response = await _IAMService.DeleteRoleAsync(new DeleteRoleRequest { RoleName = roleName }); return response.HttpStatusCode == System.Net.HttpStatusCode.OK; } /// <summary> /// Delete an IAM role policy. /// </summary> /// <param name="roleName">The name of the IAM role.</param> /// <param name="policyName">The name of the IAM role policy to delete.</param> /// <returns>A Boolean value indicating the success of the action.</returns> public async Task<bool> DeleteRolePolicyAsync(string roleName, string policyName) { var response = await _IAMService.DeleteRolePolicyAsync(new DeleteRolePolicyRequest { PolicyName = policyName, RoleName = roleName, }); return response.HttpStatusCode == System.Net.HttpStatusCode.OK; } /// <summary> /// Delete an IAM user. /// </summary> /// <param name="userName">The username of the IAM user to delete.</param> /// <returns>A Boolean value indicating the success of the action.</returns> public async Task<bool> DeleteUserAsync(string userName) { var response = await _IAMService.DeleteUserAsync(new DeleteUserRequest { UserName = userName }); return response.HttpStatusCode == System.Net.HttpStatusCode.OK; } /// <summary> /// Delete an IAM user policy. /// </summary> /// <param name="policyName">The name of the IAM policy to delete.</param> /// <param name="userName">The username of the IAM user.</param> /// <returns>A Boolean value indicating the success of the action.</returns> public async Task<bool> DeleteUserPolicyAsync(string policyName, string userName) { var response = await _IAMService.DeleteUserPolicyAsync(new DeleteUserPolicyRequest { PolicyName = policyName, UserName = userName }); return response.HttpStatusCode == System.Net.HttpStatusCode.OK; } /// <summary> /// Detach an IAM policy from an IAM role. /// </summary> /// <param name="policyArn">The Amazon Resource Name (ARN) of the IAM policy.</param> /// <param name="roleName">The name of the IAM role.</param> /// <returns>A Boolean value indicating the success of the action.</returns> public async Task<bool> DetachRolePolicyAsync(string policyArn, string roleName) { var response = await _IAMService.DetachRolePolicyAsync(new DetachRolePolicyRequest { PolicyArn = policyArn, RoleName = roleName, }); return response.HttpStatusCode == System.Net.HttpStatusCode.OK; } /// <summary> /// Gets the IAM password policy for an AWS account. /// </summary> /// <returns>The PasswordPolicy for the AWS account.</returns> public async Task<PasswordPolicy> GetAccountPasswordPolicyAsync() { var response = await _IAMService.GetAccountPasswordPolicyAsync(new GetAccountPasswordPolicyRequest()); return response.PasswordPolicy; } /// <summary> /// Get information about an IAM policy. /// </summary> /// <param name="policyArn">The IAM policy to retrieve information for.</param> /// <returns>The IAM policy.</returns> public async Task<ManagedPolicy> GetPolicyAsync(string policyArn) { var response = await _IAMService.GetPolicyAsync(new GetPolicyRequest { PolicyArn = policyArn }); return response.Policy; } /// <summary> /// Get information about an IAM role. /// </summary> /// <param name="roleName">The name of the IAM role to retrieve information /// for.</param> /// <returns>The IAM role that was retrieved.</returns> public async Task<Role> GetRoleAsync(string roleName) { var response = await _IAMService.GetRoleAsync(new GetRoleRequest { RoleName = roleName, }); return response.Role; } /// <summary> /// Get information about an IAM user. /// </summary> /// <param name="userName">The username of the user.</param> /// <returns>An IAM user object.</returns> public async Task<User> GetUserAsync(string userName) { var response = await _IAMService.GetUserAsync(new GetUserRequest { UserName = userName }); return response.User; } /// <summary> /// List the IAM role policies that are attached to an IAM role. /// </summary> /// <param name="roleName">The IAM role to list IAM policies for.</param> /// <returns>A list of the IAM policies attached to the IAM role.</returns> public async Task<List<AttachedPolicyType>> ListAttachedRolePoliciesAsync(string roleName) { var attachedPolicies = new List<AttachedPolicyType>(); var attachedRolePoliciesPaginator = _IAMService.Paginators.ListAttachedRolePolicies(new ListAttachedRolePoliciesRequest { RoleName = roleName }); await foreach (var response in attachedRolePoliciesPaginator.Responses) { attachedPolicies.AddRange(response.AttachedPolicies); } return attachedPolicies; } /// <summary> /// List IAM groups. /// </summary> /// <returns>A list of IAM groups.</returns> public async Task<List<Group>> ListGroupsAsync() { var groupsPaginator = _IAMService.Paginators.ListGroups(new ListGroupsRequest()); var groups = new List<Group>(); await foreach (var response in groupsPaginator.Responses) { groups.AddRange(response.Groups); } return groups; } /// <summary> /// List IAM policies. /// </summary> /// <returns>A list of the IAM policies.</returns> public async Task<List<ManagedPolicy>> ListPoliciesAsync() { var listPoliciesPaginator = _IAMService.Paginators.ListPolicies(new ListPoliciesRequest()); var policies = new List<ManagedPolicy>(); await foreach (var response in listPoliciesPaginator.Responses) { policies.AddRange(response.Policies); } return policies; } /// <summary> /// List IAM role policies. /// </summary> /// <param name="roleName">The IAM role for which to list IAM policies.</param> /// <returns>A list of IAM policy names.</returns> public async Task<List<string>> ListRolePoliciesAsync(string roleName) { var listRolePoliciesPaginator = _IAMService.Paginators.ListRolePolicies(new ListRolePoliciesRequest { RoleName = roleName }); var policyNames = new List<string>(); await foreach (var response in listRolePoliciesPaginator.Responses) { policyNames.AddRange(response.PolicyNames); } return policyNames; } /// <summary> /// List IAM roles. /// </summary> /// <returns>A list of IAM roles.</returns> public async Task<List<Role>> ListRolesAsync() { var listRolesPaginator = _IAMService.Paginators.ListRoles(new ListRolesRequest()); var roles = new List<Role>(); await foreach (var response in listRolesPaginator.Responses) { roles.AddRange(response.Roles); } return roles; } /// <summary> /// List SAML authentication providers. /// </summary> /// <returns>A list of SAML providers.</returns> public async Task<List<SAMLProviderListEntry>> ListSAMLProvidersAsync() { var response = await _IAMService.ListSAMLProvidersAsync(new ListSAMLProvidersRequest()); return response.SAMLProviderList; } /// <summary> /// List IAM users. /// </summary> /// <returns>A list of IAM users.</returns> public async Task<List<User>> ListUsersAsync() { var listUsersPaginator = _IAMService.Paginators.ListUsers(new ListUsersRequest()); var users = new List<User>(); await foreach (var response in listUsersPaginator.Responses) { users.AddRange(response.Users); } return users; } /// <summary> /// Remove a user from an IAM group. /// </summary> /// <param name="userName">The username of the user to remove.</param> /// <param name="groupName">The name of the IAM group to remove the user from.</param> /// <returns>A Boolean value indicating the success of the action.</returns> public async Task<bool> RemoveUserFromGroupAsync(string userName, string groupName) { // Remove the user from the group. var removeUserRequest = new RemoveUserFromGroupRequest() { UserName = userName, GroupName = groupName, }; var response = await _IAMService.RemoveUserFromGroupAsync(removeUserRequest); return response.HttpStatusCode == HttpStatusCode.OK; } /// <summary> /// Add or update an inline policy document that is embedded in an IAM group. /// </summary> /// <param name="groupName">The name of the IAM group.</param> /// <param name="policyName">The name of the IAM policy.</param> /// <param name="policyDocument">The policy document defining the IAM policy.</param> /// <returns>A Boolean value indicating the success of the action.</returns> public async Task<bool> PutGroupPolicyAsync(string groupName, string policyName, string policyDocument) { var request = new PutGroupPolicyRequest { GroupName = groupName, PolicyName = policyName, PolicyDocument = policyDocument }; var response = await _IAMService.PutGroupPolicyAsync(request); return response.HttpStatusCode == System.Net.HttpStatusCode.OK; } /// <summary> /// Update the inline policy document embedded in a role. /// </summary> /// <param name="policyName">The name of the policy to embed.</param> /// <param name="roleName">The name of the role to update.</param> /// <param name="policyDocument">The policy document that defines the role.</param> /// <returns>A Boolean value indicating the success of the action.</returns> public async Task<bool> PutRolePolicyAsync(string policyName, string roleName, string policyDocument) { var request = new PutRolePolicyRequest { PolicyName = policyName, RoleName = roleName, PolicyDocument = policyDocument }; var response = await _IAMService.PutRolePolicyAsync(request); return response.HttpStatusCode == HttpStatusCode.OK; } /// <summary> /// Add or update an inline policy document that is embedded in an IAM user. /// </summary> /// <param name="userName">The name of the IAM user.</param> /// <param name="policyName">The name of the IAM policy.</param> /// <param name="policyDocument">The policy document defining the IAM policy.</param> /// <returns>A Boolean value indicating the success of the action.</returns> public async Task<bool> PutUserPolicyAsync(string userName, string policyName, string policyDocument) { var request = new PutUserPolicyRequest { UserName = userName, PolicyName = policyName, PolicyDocument = policyDocument }; var response = await _IAMService.PutUserPolicyAsync(request); return response.HttpStatusCode == System.Net.HttpStatusCode.OK; } /// <summary> /// Wait for a new access key to be ready to use. /// </summary> /// <param name="accessKeyId">The Id of the access key.</param> /// <returns>A boolean value indicating the success of the action.</returns> public async Task<bool> WaitUntilAccessKeyIsReady(string accessKeyId) { var keyReady = false; do { try { var response = await _IAMService.GetAccessKeyLastUsedAsync( new GetAccessKeyLastUsedRequest { AccessKeyId = accessKeyId }); if (response.UserName is not null) { keyReady = true; } } catch (NoSuchEntityException) { keyReady = false; } } while (!keyReady); return keyReady; } } using Microsoft.Extensions.Configuration; namespace IAMGroups; public class IAMGroups { private static ILogger logger = null!; // Represents JSON code for AWS full access policy for Amazon Simple // Storage Service (Amazon S3). private const string S3FullAccessPolicyDocument = "{" + " \"Statement\" : [{" + " \"Action\" : [\"s3:*\"]," + " \"Effect\" : \"Allow\"," + " \"Resource\" : \"*\"" + "}]" + "}"; static async Task Main(string[] args) { // Set up dependency injection for the AWS service. using var host = Host.CreateDefaultBuilder(args) .ConfigureLogging(logging => logging.AddFilter("System", LogLevel.Debug) .AddFilter<DebugLoggerProvider>("Microsoft", LogLevel.Information) .AddFilter<ConsoleLoggerProvider>("Microsoft", LogLevel.Trace)) .ConfigureServices((_, services) => services.AddAWSService<IAmazonIdentityManagementService>() .AddTransient<IAMWrapper>() .AddTransient<UIWrapper>() ) .Build(); logger = LoggerFactory.Create(builder => { builder.AddConsole(); }) .CreateLogger<IAMGroups>(); IConfiguration configuration = new ConfigurationBuilder() .SetBasePath(Directory.GetCurrentDirectory()) .AddJsonFile("settings.json") // Load test settings from .json file. .AddJsonFile("settings.local.json", true) // Optionally load local settings. .Build(); var groupUserName = configuration["GroupUserName"]; var groupName = configuration["GroupName"]; var groupPolicyName = configuration["GroupPolicyName"]; var groupBucketName = configuration["GroupBucketName"]; var wrapper = host.Services.GetRequiredService<IAMWrapper>(); var uiWrapper = host.Services.GetRequiredService<UIWrapper>(); uiWrapper.DisplayGroupsOverview(); uiWrapper.PressEnter(); // Create an IAM group. uiWrapper.DisplayTitle("Create IAM group"); Console.WriteLine("Let's begin by creating a new IAM group."); var group = await wrapper.CreateGroupAsync(groupName); // Add an inline IAM policy to the group. uiWrapper.DisplayTitle("Add policy to group"); Console.WriteLine("Add an inline policy to the group that allows members to have full access to"); Console.WriteLine("Amazon Simple Storage Service (Amazon S3) buckets."); await wrapper.PutGroupPolicyAsync(group.GroupName, groupPolicyName, S3FullAccessPolicyDocument); uiWrapper.PressEnter(); // Now create a new user. uiWrapper.DisplayTitle("Create an IAM user"); Console.WriteLine("Now let's create a new IAM user."); var groupUser = await wrapper.CreateUserAsync(groupUserName); // Add the new user to the group. uiWrapper.DisplayTitle("Add the user to the group"); Console.WriteLine("Adding the user to the group, which will give the user the same permissions as the group."); await wrapper.AddUserToGroupAsync(groupUser.UserName, group.GroupName); Console.WriteLine($"User, {groupUser.UserName}, has been added to the group, {group.GroupName}."); uiWrapper.PressEnter(); Console.WriteLine("Now that we have created a user, and added the user to the group, let's create an IAM access key."); // Create access and secret keys for the user. var accessKey = await wrapper.CreateAccessKeyAsync(groupUserName); Console.WriteLine("Key created."); uiWrapper.WaitABit(15, "Waiting for the access key to be ready for use."); uiWrapper.DisplayTitle("List buckets"); Console.WriteLine("To prove that the user has access to Amazon S3, list the S3 buckets for the account."); var s3Client = new AmazonS3Client(accessKey.AccessKeyId, accessKey.SecretAccessKey); var stsClient = new AmazonSecurityTokenServiceClient(accessKey.AccessKeyId, accessKey.SecretAccessKey); var s3Wrapper = new S3Wrapper(s3Client, stsClient); var buckets = await s3Wrapper.ListMyBucketsAsync(); if (buckets is not null) { buckets.ForEach(bucket => { Console.WriteLine($"{bucket.BucketName}\tcreated on: {bucket.CreationDate}"); }); } // Show that the user also has write access to Amazon S3 by creating // a new bucket. uiWrapper.DisplayTitle("Create a bucket"); Console.WriteLine("Since group members have full access to Amazon S3, let's create a bucket."); var success = await s3Wrapper.PutBucketAsync(groupBucketName); if (success) { Console.WriteLine($"Successfully created the bucket: {groupBucketName}."); } uiWrapper.PressEnter(); Console.WriteLine("Let's list the user's S3 buckets again to show the new bucket."); buckets = await s3Wrapper.ListMyBucketsAsync(); if (buckets is not null) { buckets.ForEach(bucket => { Console.WriteLine($"{bucket.BucketName}\tcreated on: {bucket.CreationDate}"); }); } uiWrapper.PressEnter(); uiWrapper.DisplayTitle("Clean up resources"); Console.WriteLine("First delete the bucket we created."); await s3Wrapper.DeleteBucketAsync(groupBucketName); Console.WriteLine($"Now remove the user, {groupUserName}, from the group, {groupName}."); await wrapper.RemoveUserFromGroupAsync(groupUserName, groupName); Console.WriteLine("Delete the user's access key."); await wrapper.DeleteAccessKeyAsync(accessKey.AccessKeyId, groupUserName); // Now we can safely delete the user. Console.WriteLine("Now we can delete the user."); await wrapper.DeleteUserAsync(groupUserName); uiWrapper.PressEnter(); Console.WriteLine("Now we will delete the IAM policy attached to the group."); await wrapper.DeleteGroupPolicyAsync(groupName, groupPolicyName); Console.WriteLine("Now we delete the IAM group."); await wrapper.DeleteGroupAsync(groupName); uiWrapper.PressEnter(); Console.WriteLine("The IAM groups demo has completed."); uiWrapper.PressEnter(); } } namespace IamScenariosCommon; using System.Net; /// <summary> /// A class to perform Amazon Simple Storage Service (Amazon S3) actions for /// the IAM Basics scenario. /// </summary> public class S3Wrapper { private IAmazonS3 _s3Service; private IAmazonSecurityTokenService _stsService; /// <summary> /// Constructor for the S3Wrapper class. /// </summary> /// <param name="s3Service">An Amazon S3 client object.</param> /// <param name="stsService">An AWS Security Token Service (AWS STS) /// client object.</param> public S3Wrapper(IAmazonS3 s3Service, IAmazonSecurityTokenService stsService) { _s3Service = s3Service; _stsService = stsService; } /// <summary> /// Assumes an AWS Identity and Access Management (IAM) role that allows /// Amazon S3 access for the current session. /// </summary> /// <param name="roleSession">A string representing the current session.</param> /// <param name="roleToAssume">The name of the IAM role to assume.</param> /// <returns>Credentials for the newly assumed IAM role.</returns> public async Task<Credentials> AssumeS3RoleAsync(string roleSession, string roleToAssume) { // Create the request to use with the AssumeRoleAsync call. var request = new AssumeRoleRequest() { RoleSessionName = roleSession, RoleArn = roleToAssume, }; var response = await _stsService.AssumeRoleAsync(request); return response.Credentials; } /// <summary> /// Delete an S3 bucket. /// </summary> /// <param name="bucketName">Name of the S3 bucket to delete.</param> /// <returns>A Boolean value indicating the success of the action.</returns> public async Task<bool> DeleteBucketAsync(string bucketName) { var result = await _s3Service.DeleteBucketAsync(new DeleteBucketRequest { BucketName = bucketName }); return result.HttpStatusCode == HttpStatusCode.OK; } /// <summary> /// List the buckets that are owned by the user's account. /// </summary> /// <returns>Async Task.</returns> public async Task<List<S3Bucket>?> ListMyBucketsAsync() { try { // Get the list of buckets accessible by the new user. var response = await _s3Service.ListBucketsAsync(); return response.Buckets; } catch (AmazonS3Exception ex) { // Something else went wrong. Display the error message. Console.WriteLine($"Error: {ex.Message}"); return null; } } /// <summary> /// Create a new S3 bucket. /// </summary> /// <param name="bucketName">The name for the new bucket.</param> /// <returns>A Boolean value indicating whether the action completed /// successfully.</returns> public async Task<bool> PutBucketAsync(string bucketName) { var response = await _s3Service.PutBucketAsync(new PutBucketRequest { BucketName = bucketName }); return response.HttpStatusCode == HttpStatusCode.OK; } /// <summary> /// Update the client objects with new client objects. This is available /// because the scenario uses the methods of this class without and then /// with the proper permissions to list S3 buckets. /// </summary> /// <param name="s3Service">The Amazon S3 client object.</param> /// <param name="stsService">The AWS STS client object.</param> public void UpdateClients(IAmazonS3 s3Service, IAmazonSecurityTokenService stsService) { _s3Service = s3Service; _stsService = stsService; } } namespace IamScenariosCommon; public class UIWrapper { public readonly string SepBar = new('-', Console.WindowWidth); /// <summary> /// Show information about the IAM Groups scenario. /// </summary> public void DisplayGroupsOverview() { Console.Clear(); DisplayTitle("Welcome to the IAM Groups Demo"); Console.WriteLine("This example application does the following:"); Console.WriteLine("\t1. Creates an Amazon Identity and Access Management (IAM) group."); Console.WriteLine("\t2. Adds an IAM policy to the IAM group giving it full access to Amazon S3."); Console.WriteLine("\t3. Creates a new IAM user."); Console.WriteLine("\t4. Creates an IAM access key for the user."); Console.WriteLine("\t5. Adds the user to the IAM group."); Console.WriteLine("\t6. Lists the buckets on the account."); Console.WriteLine("\t7. Proves that the user has full Amazon S3 access by creating a bucket."); Console.WriteLine("\t8. List the buckets again to show the new bucket."); Console.WriteLine("\t9. Cleans up all the resources created."); } /// <summary> /// Show information about the IAM Basics scenario. /// </summary> public void DisplayBasicsOverview() { Console.Clear(); DisplayTitle("Welcome to IAM Basics"); Console.WriteLine("This example application does the following:"); Console.WriteLine("\t1. Creates a user with no permissions."); Console.WriteLine("\t2. Creates a role and policy that grant s3:ListAllMyBuckets permission."); Console.WriteLine("\t3. Grants the user permission to assume the role."); Console.WriteLine("\t4. Creates an S3 client object as the user and tries to list buckets (this will fail)."); Console.WriteLine("\t5. Gets temporary credentials by assuming the role."); Console.WriteLine("\t6. Creates a new S3 client object with the temporary credentials and lists the buckets (this will succeed)."); Console.WriteLine("\t7. Deletes all the resources."); } /// <summary> /// Display a message and wait until the user presses enter. /// </summary> public void PressEnter() { Console.Write("\nPress <Enter> to continue. "); _ = Console.ReadLine(); Console.WriteLine(); } /// <summary> /// Pad a string with spaces to center it on the console display. /// </summary> /// <param name="strToCenter">The string to be centered.</param> /// <returns>The padded string.</returns> public string CenterString(string strToCenter) { var padAmount = (Console.WindowWidth - strToCenter.Length) / 2; var leftPad = new string(' ', padAmount); return $"{leftPad}{strToCenter}"; } /// <summary> /// Display a line of hyphens, the centered text of the title, and another /// line of hyphens. /// </summary> /// <param name="strTitle">The string to be displayed.</param> public void DisplayTitle(string strTitle) { Console.WriteLine(SepBar); Console.WriteLine(CenterString(strTitle)); Console.WriteLine(SepBar); } /// <summary> /// Display a countdown and wait for a number of seconds. /// </summary> /// <param name="numSeconds">The number of seconds to wait.</param> public void WaitABit(int numSeconds, string msg) { Console.WriteLine(msg); // Wait for the requested number of seconds. for (int i = numSeconds; i > 0; i--) { System.Threading.Thread.Sleep(1000); Console.Write($"{i}..."); } PressEnter(); } }

以下代码示例演示了如何创建用户并代入角色。

警告

为了避免安全风险,在开发专用软件或处理真实数据时,请勿使用 IAM 用户进行身份验证,而是使用与身份提供商的联合身份验证,例如 Amazon IAM Identity Center

  • 创建没有权限的用户。

  • 创建授予列出账户的 Amazon S3 存储桶的权限的角色

  • 添加策略以允许用户代入该角色。

  • 代入角色并使用临时凭证列出 S3 存储桶,然后清除资源。

Amazon SDK for .NET
注意

还有更多相关信息 GitHub。在 Amazon 代码示例存储库中查找完整示例,了解如何进行设置和运行。

global using Amazon.IdentityManagement; global using Amazon.S3; global using Amazon.SecurityToken; global using IAMActions; global using IamScenariosCommon; global using Microsoft.Extensions.DependencyInjection; global using Microsoft.Extensions.Hosting; global using Microsoft.Extensions.Logging; global using Microsoft.Extensions.Logging.Console; global using Microsoft.Extensions.Logging.Debug; namespace IAMActions; public class IAMWrapper { private readonly IAmazonIdentityManagementService _IAMService; /// <summary> /// Constructor for the IAMWrapper class. /// </summary> /// <param name="IAMService">An IAM client object.</param> public IAMWrapper(IAmazonIdentityManagementService IAMService) { _IAMService = IAMService; } /// <summary> /// Add an existing IAM user to an existing IAM group. /// </summary> /// <param name="userName">The username of the user to add.</param> /// <param name="groupName">The name of the group to add the user to.</param> /// <returns>A Boolean value indicating the success of the action.</returns> public async Task<bool> AddUserToGroupAsync(string userName, string groupName) { var response = await _IAMService.AddUserToGroupAsync(new AddUserToGroupRequest { GroupName = groupName, UserName = userName, }); return response.HttpStatusCode == HttpStatusCode.OK; } /// <summary> /// Attach an IAM policy to a role. /// </summary> /// <param name="policyArn">The policy to attach.</param> /// <param name="roleName">The role that the policy will be attached to.</param> /// <returns>A Boolean value indicating the success of the action.</returns> public async Task<bool> AttachRolePolicyAsync(string policyArn, string roleName) { var response = await _IAMService.AttachRolePolicyAsync(new AttachRolePolicyRequest { PolicyArn = policyArn, RoleName = roleName, }); return response.HttpStatusCode == System.Net.HttpStatusCode.OK; } /// <summary> /// Create an IAM access key for a user. /// </summary> /// <param name="userName">The username for which to create the IAM access /// key.</param> /// <returns>The AccessKey.</returns> public async Task<AccessKey> CreateAccessKeyAsync(string userName) { var response = await _IAMService.CreateAccessKeyAsync(new CreateAccessKeyRequest { UserName = userName, }); return response.AccessKey; } /// <summary> /// Create an IAM group. /// </summary> /// <param name="groupName">The name to give the IAM group.</param> /// <returns>The IAM group that was created.</returns> public async Task<Group> CreateGroupAsync(string groupName) { var response = await _IAMService.CreateGroupAsync(new CreateGroupRequest { GroupName = groupName }); return response.Group; } /// <summary> /// Create an IAM policy. /// </summary> /// <param name="policyName">The name to give the new IAM policy.</param> /// <param name="policyDocument">The policy document for the new policy.</param> /// <returns>The new IAM policy object.</returns> public async Task<ManagedPolicy> CreatePolicyAsync(string policyName, string policyDocument) { var response = await _IAMService.CreatePolicyAsync(new CreatePolicyRequest { PolicyDocument = policyDocument, PolicyName = policyName, }); return response.Policy; } /// <summary> /// Create a new IAM role. /// </summary> /// <param name="roleName">The name of the IAM role.</param> /// <param name="rolePolicyDocument">The name of the IAM policy document /// for the new role.</param> /// <returns>The Amazon Resource Name (ARN) of the role.</returns> public async Task<string> CreateRoleAsync(string roleName, string rolePolicyDocument) { var request = new CreateRoleRequest { RoleName = roleName, AssumeRolePolicyDocument = rolePolicyDocument, }; var response = await _IAMService.CreateRoleAsync(request); return response.Role.Arn; } /// <summary> /// Create an IAM service-linked role. /// </summary> /// <param name="serviceName">The name of the AWS Service.</param> /// <param name="description">A description of the IAM service-linked role.</param> /// <returns>The IAM role that was created.</returns> public async Task<Role> CreateServiceLinkedRoleAsync(string serviceName, string description) { var request = new CreateServiceLinkedRoleRequest { AWSServiceName = serviceName, Description = description }; var response = await _IAMService.CreateServiceLinkedRoleAsync(request); return response.Role; } /// <summary> /// Create an IAM user. /// </summary> /// <param name="userName">The username for the new IAM user.</param> /// <returns>The IAM user that was created.</returns> public async Task<User> CreateUserAsync(string userName) { var response = await _IAMService.CreateUserAsync(new CreateUserRequest { UserName = userName }); return response.User; } /// <summary> /// Delete an IAM user's access key. /// </summary> /// <param name="accessKeyId">The Id for the IAM access key.</param> /// <param name="userName">The username of the user that owns the IAM /// access key.</param> /// <returns>A Boolean value indicating the success of the action.</returns> public async Task<bool> DeleteAccessKeyAsync(string accessKeyId, string userName) { var response = await _IAMService.DeleteAccessKeyAsync(new DeleteAccessKeyRequest { AccessKeyId = accessKeyId, UserName = userName, }); return response.HttpStatusCode == System.Net.HttpStatusCode.OK; } /// <summary> /// Delete an IAM group. /// </summary> /// <param name="groupName">The name of the IAM group to delete.</param> /// <returns>A Boolean value indicating the success of the action.</returns> public async Task<bool> DeleteGroupAsync(string groupName) { var response = await _IAMService.DeleteGroupAsync(new DeleteGroupRequest { GroupName = groupName }); return response.HttpStatusCode == HttpStatusCode.OK; } /// <summary> /// Delete an IAM policy associated with an IAM group. /// </summary> /// <param name="groupName">The name of the IAM group associated with the /// policy.</param> /// <param name="policyName">The name of the policy to delete.</param> /// <returns>A Boolean value indicating the success of the action.</returns> public async Task<bool> DeleteGroupPolicyAsync(string groupName, string policyName) { var request = new DeleteGroupPolicyRequest() { GroupName = groupName, PolicyName = policyName, }; var response = await _IAMService.DeleteGroupPolicyAsync(request); return response.HttpStatusCode == System.Net.HttpStatusCode.OK; } /// <summary> /// Delete an IAM policy. /// </summary> /// <param name="policyArn">The Amazon Resource Name (ARN) of the policy to /// delete.</param> /// <returns>A Boolean value indicating the success of the action.</returns> public async Task<bool> DeletePolicyAsync(string policyArn) { var response = await _IAMService.DeletePolicyAsync(new DeletePolicyRequest { PolicyArn = policyArn }); return response.HttpStatusCode == System.Net.HttpStatusCode.OK; } /// <summary> /// Delete an IAM role. /// </summary> /// <param name="roleName">The name of the IAM role to delete.</param> /// <returns>A Boolean value indicating the success of the action.</returns> public async Task<bool> DeleteRoleAsync(string roleName) { var response = await _IAMService.DeleteRoleAsync(new DeleteRoleRequest { RoleName = roleName }); return response.HttpStatusCode == System.Net.HttpStatusCode.OK; } /// <summary> /// Delete an IAM role policy. /// </summary> /// <param name="roleName">The name of the IAM role.</param> /// <param name="policyName">The name of the IAM role policy to delete.</param> /// <returns>A Boolean value indicating the success of the action.</returns> public async Task<bool> DeleteRolePolicyAsync(string roleName, string policyName) { var response = await _IAMService.DeleteRolePolicyAsync(new DeleteRolePolicyRequest { PolicyName = policyName, RoleName = roleName, }); return response.HttpStatusCode == System.Net.HttpStatusCode.OK; } /// <summary> /// Delete an IAM user. /// </summary> /// <param name="userName">The username of the IAM user to delete.</param> /// <returns>A Boolean value indicating the success of the action.</returns> public async Task<bool> DeleteUserAsync(string userName) { var response = await _IAMService.DeleteUserAsync(new DeleteUserRequest { UserName = userName }); return response.HttpStatusCode == System.Net.HttpStatusCode.OK; } /// <summary> /// Delete an IAM user policy. /// </summary> /// <param name="policyName">The name of the IAM policy to delete.</param> /// <param name="userName">The username of the IAM user.</param> /// <returns>A Boolean value indicating the success of the action.</returns> public async Task<bool> DeleteUserPolicyAsync(string policyName, string userName) { var response = await _IAMService.DeleteUserPolicyAsync(new DeleteUserPolicyRequest { PolicyName = policyName, UserName = userName }); return response.HttpStatusCode == System.Net.HttpStatusCode.OK; } /// <summary> /// Detach an IAM policy from an IAM role. /// </summary> /// <param name="policyArn">The Amazon Resource Name (ARN) of the IAM policy.</param> /// <param name="roleName">The name of the IAM role.</param> /// <returns>A Boolean value indicating the success of the action.</returns> public async Task<bool> DetachRolePolicyAsync(string policyArn, string roleName) { var response = await _IAMService.DetachRolePolicyAsync(new DetachRolePolicyRequest { PolicyArn = policyArn, RoleName = roleName, }); return response.HttpStatusCode == System.Net.HttpStatusCode.OK; } /// <summary> /// Gets the IAM password policy for an AWS account. /// </summary> /// <returns>The PasswordPolicy for the AWS account.</returns> public async Task<PasswordPolicy> GetAccountPasswordPolicyAsync() { var response = await _IAMService.GetAccountPasswordPolicyAsync(new GetAccountPasswordPolicyRequest()); return response.PasswordPolicy; } /// <summary> /// Get information about an IAM policy. /// </summary> /// <param name="policyArn">The IAM policy to retrieve information for.</param> /// <returns>The IAM policy.</returns> public async Task<ManagedPolicy> GetPolicyAsync(string policyArn) { var response = await _IAMService.GetPolicyAsync(new GetPolicyRequest { PolicyArn = policyArn }); return response.Policy; } /// <summary> /// Get information about an IAM role. /// </summary> /// <param name="roleName">The name of the IAM role to retrieve information /// for.</param> /// <returns>The IAM role that was retrieved.</returns> public async Task<Role> GetRoleAsync(string roleName) { var response = await _IAMService.GetRoleAsync(new GetRoleRequest { RoleName = roleName, }); return response.Role; } /// <summary> /// Get information about an IAM user. /// </summary> /// <param name="userName">The username of the user.</param> /// <returns>An IAM user object.</returns> public async Task<User> GetUserAsync(string userName) { var response = await _IAMService.GetUserAsync(new GetUserRequest { UserName = userName }); return response.User; } /// <summary> /// List the IAM role policies that are attached to an IAM role. /// </summary> /// <param name="roleName">The IAM role to list IAM policies for.</param> /// <returns>A list of the IAM policies attached to the IAM role.</returns> public async Task<List<AttachedPolicyType>> ListAttachedRolePoliciesAsync(string roleName) { var attachedPolicies = new List<AttachedPolicyType>(); var attachedRolePoliciesPaginator = _IAMService.Paginators.ListAttachedRolePolicies(new ListAttachedRolePoliciesRequest { RoleName = roleName }); await foreach (var response in attachedRolePoliciesPaginator.Responses) { attachedPolicies.AddRange(response.AttachedPolicies); } return attachedPolicies; } /// <summary> /// List IAM groups. /// </summary> /// <returns>A list of IAM groups.</returns> public async Task<List<Group>> ListGroupsAsync() { var groupsPaginator = _IAMService.Paginators.ListGroups(new ListGroupsRequest()); var groups = new List<Group>(); await foreach (var response in groupsPaginator.Responses) { groups.AddRange(response.Groups); } return groups; } /// <summary> /// List IAM policies. /// </summary> /// <returns>A list of the IAM policies.</returns> public async Task<List<ManagedPolicy>> ListPoliciesAsync() { var listPoliciesPaginator = _IAMService.Paginators.ListPolicies(new ListPoliciesRequest()); var policies = new List<ManagedPolicy>(); await foreach (var response in listPoliciesPaginator.Responses) { policies.AddRange(response.Policies); } return policies; } /// <summary> /// List IAM role policies. /// </summary> /// <param name="roleName">The IAM role for which to list IAM policies.</param> /// <returns>A list of IAM policy names.</returns> public async Task<List<string>> ListRolePoliciesAsync(string roleName) { var listRolePoliciesPaginator = _IAMService.Paginators.ListRolePolicies(new ListRolePoliciesRequest { RoleName = roleName }); var policyNames = new List<string>(); await foreach (var response in listRolePoliciesPaginator.Responses) { policyNames.AddRange(response.PolicyNames); } return policyNames; } /// <summary> /// List IAM roles. /// </summary> /// <returns>A list of IAM roles.</returns> public async Task<List<Role>> ListRolesAsync() { var listRolesPaginator = _IAMService.Paginators.ListRoles(new ListRolesRequest()); var roles = new List<Role>(); await foreach (var response in listRolesPaginator.Responses) { roles.AddRange(response.Roles); } return roles; } /// <summary> /// List SAML authentication providers. /// </summary> /// <returns>A list of SAML providers.</returns> public async Task<List<SAMLProviderListEntry>> ListSAMLProvidersAsync() { var response = await _IAMService.ListSAMLProvidersAsync(new ListSAMLProvidersRequest()); return response.SAMLProviderList; } /// <summary> /// List IAM users. /// </summary> /// <returns>A list of IAM users.</returns> public async Task<List<User>> ListUsersAsync() { var listUsersPaginator = _IAMService.Paginators.ListUsers(new ListUsersRequest()); var users = new List<User>(); await foreach (var response in listUsersPaginator.Responses) { users.AddRange(response.Users); } return users; } /// <summary> /// Remove a user from an IAM group. /// </summary> /// <param name="userName">The username of the user to remove.</param> /// <param name="groupName">The name of the IAM group to remove the user from.</param> /// <returns>A Boolean value indicating the success of the action.</returns> public async Task<bool> RemoveUserFromGroupAsync(string userName, string groupName) { // Remove the user from the group. var removeUserRequest = new RemoveUserFromGroupRequest() { UserName = userName, GroupName = groupName, }; var response = await _IAMService.RemoveUserFromGroupAsync(removeUserRequest); return response.HttpStatusCode == HttpStatusCode.OK; } /// <summary> /// Add or update an inline policy document that is embedded in an IAM group. /// </summary> /// <param name="groupName">The name of the IAM group.</param> /// <param name="policyName">The name of the IAM policy.</param> /// <param name="policyDocument">The policy document defining the IAM policy.</param> /// <returns>A Boolean value indicating the success of the action.</returns> public async Task<bool> PutGroupPolicyAsync(string groupName, string policyName, string policyDocument) { var request = new PutGroupPolicyRequest { GroupName = groupName, PolicyName = policyName, PolicyDocument = policyDocument }; var response = await _IAMService.PutGroupPolicyAsync(request); return response.HttpStatusCode == System.Net.HttpStatusCode.OK; } /// <summary> /// Update the inline policy document embedded in a role. /// </summary> /// <param name="policyName">The name of the policy to embed.</param> /// <param name="roleName">The name of the role to update.</param> /// <param name="policyDocument">The policy document that defines the role.</param> /// <returns>A Boolean value indicating the success of the action.</returns> public async Task<bool> PutRolePolicyAsync(string policyName, string roleName, string policyDocument) { var request = new PutRolePolicyRequest { PolicyName = policyName, RoleName = roleName, PolicyDocument = policyDocument }; var response = await _IAMService.PutRolePolicyAsync(request); return response.HttpStatusCode == HttpStatusCode.OK; } /// <summary> /// Add or update an inline policy document that is embedded in an IAM user. /// </summary> /// <param name="userName">The name of the IAM user.</param> /// <param name="policyName">The name of the IAM policy.</param> /// <param name="policyDocument">The policy document defining the IAM policy.</param> /// <returns>A Boolean value indicating the success of the action.</returns> public async Task<bool> PutUserPolicyAsync(string userName, string policyName, string policyDocument) { var request = new PutUserPolicyRequest { UserName = userName, PolicyName = policyName, PolicyDocument = policyDocument }; var response = await _IAMService.PutUserPolicyAsync(request); return response.HttpStatusCode == System.Net.HttpStatusCode.OK; } /// <summary> /// Wait for a new access key to be ready to use. /// </summary> /// <param name="accessKeyId">The Id of the access key.</param> /// <returns>A boolean value indicating the success of the action.</returns> public async Task<bool> WaitUntilAccessKeyIsReady(string accessKeyId) { var keyReady = false; do { try { var response = await _IAMService.GetAccessKeyLastUsedAsync( new GetAccessKeyLastUsedRequest { AccessKeyId = accessKeyId }); if (response.UserName is not null) { keyReady = true; } } catch (NoSuchEntityException) { keyReady = false; } } while (!keyReady); return keyReady; } } using Microsoft.Extensions.Configuration; namespace IAMBasics; public class IAMBasics { private static ILogger logger = null!; static async Task Main(string[] args) { // Set up dependency injection for the AWS service. using var host = Host.CreateDefaultBuilder(args) .ConfigureLogging(logging => logging.AddFilter("System", LogLevel.Debug) .AddFilter<DebugLoggerProvider>("Microsoft", LogLevel.Information) .AddFilter<ConsoleLoggerProvider>("Microsoft", LogLevel.Trace)) .ConfigureServices((_, services) => services.AddAWSService<IAmazonIdentityManagementService>() .AddTransient<IAMWrapper>() .AddTransient<UIWrapper>() ) .Build(); logger = LoggerFactory.Create(builder => { builder.AddConsole(); }) .CreateLogger<IAMBasics>(); IConfiguration configuration = new ConfigurationBuilder() .SetBasePath(Directory.GetCurrentDirectory()) .AddJsonFile("settings.json") // Load test settings from .json file. .AddJsonFile("settings.local.json", true) // Optionally load local settings. .Build(); // Values needed for user, role, and policies. string userName = configuration["UserName"]!; string s3PolicyName = configuration["S3PolicyName"]!; string roleName = configuration["RoleName"]!; var iamWrapper = host.Services.GetRequiredService<IAMWrapper>(); var uiWrapper = host.Services.GetRequiredService<UIWrapper>(); uiWrapper.DisplayBasicsOverview(); uiWrapper.PressEnter(); // First create a user. By default, the new user has // no permissions. uiWrapper.DisplayTitle("Create User"); Console.WriteLine($"Creating a new user with user name: {userName}."); var user = await iamWrapper.CreateUserAsync(userName); var userArn = user.Arn; Console.WriteLine($"Successfully created user: {userName} with ARN: {userArn}."); uiWrapper.WaitABit(15, "Now let's wait for the user to be ready for use."); // Define a role policy document that allows the new user // to assume the role. string assumeRolePolicyDocument = "{" + "\"Version\": \"2012-10-17\"," + "\"Statement\": [{" + "\"Effect\": \"Allow\"," + "\"Principal\": {" + $" \"AWS\": \"{userArn}\"" + "}," + "\"Action\": \"sts:AssumeRole\"" + "}]" + "}"; // Permissions to list all buckets. string policyDocument = "{" + "\"Version\": \"2012-10-17\"," + " \"Statement\" : [{" + " \"Action\" : [\"s3:ListAllMyBuckets\"]," + " \"Effect\" : \"Allow\"," + " \"Resource\" : \"*\"" + "}]" + "}"; // Create an AccessKey for the user. uiWrapper.DisplayTitle("Create access key"); Console.WriteLine("Now let's create an access key for the new user."); var accessKey = await iamWrapper.CreateAccessKeyAsync(userName); var accessKeyId = accessKey.AccessKeyId; var secretAccessKey = accessKey.SecretAccessKey; Console.WriteLine($"We have created the access key with Access key id: {accessKeyId}."); Console.WriteLine("Now let's wait until the IAM access key is ready to use."); var keyReady = await iamWrapper.WaitUntilAccessKeyIsReady(accessKeyId); // Now try listing the Amazon Simple Storage Service (Amazon S3) // buckets. This should fail at this point because the user doesn't // have permissions to perform this task. uiWrapper.DisplayTitle("Try to display Amazon S3 buckets"); Console.WriteLine("Now let's try to display a list of the user's Amazon S3 buckets."); var s3Client1 = new AmazonS3Client(accessKeyId, secretAccessKey); var stsClient1 = new AmazonSecurityTokenServiceClient(accessKeyId, secretAccessKey); var s3Wrapper = new S3Wrapper(s3Client1, stsClient1); var buckets = await s3Wrapper.ListMyBucketsAsync(); Console.WriteLine(buckets is null ? "As expected, the call to list the buckets has returned a null list." : "Something went wrong. This shouldn't have worked."); uiWrapper.PressEnter(); uiWrapper.DisplayTitle("Create IAM role"); Console.WriteLine($"Creating the role: {roleName}"); // Creating an IAM role to allow listing the S3 buckets. A role name // is not case sensitive and must be unique to the account for which it // is created. var roleArn = await iamWrapper.CreateRoleAsync(roleName, assumeRolePolicyDocument); uiWrapper.PressEnter(); // Create a policy with permissions to list S3 buckets. uiWrapper.DisplayTitle("Create IAM policy"); Console.WriteLine($"Creating the policy: {s3PolicyName}"); Console.WriteLine("with permissions to list the Amazon S3 buckets for the account."); var policy = await iamWrapper.CreatePolicyAsync(s3PolicyName, policyDocument); // Wait 15 seconds for the IAM policy to be available. uiWrapper.WaitABit(15, "Waiting for the policy to be available."); // Attach the policy to the role you created earlier. uiWrapper.DisplayTitle("Attach new IAM policy"); Console.WriteLine("Now let's attach the policy to the role."); await iamWrapper.AttachRolePolicyAsync(policy.Arn, roleName); // Wait 15 seconds for the role to be updated. Console.WriteLine(); uiWrapper.WaitABit(15, "Waiting for the policy to be attached."); // Use the AWS Security Token Service (AWS STS) to have the user // assume the role we created. var stsClient2 = new AmazonSecurityTokenServiceClient(accessKeyId, secretAccessKey); // Wait for the new credentials to become valid. uiWrapper.WaitABit(10, "Waiting for the credentials to be valid."); var assumedRoleCredentials = await s3Wrapper.AssumeS3RoleAsync("temporary-session", roleArn); // Try again to list the buckets using the client created with // the new user's credentials. This time, it should work. var s3Client2 = new AmazonS3Client(assumedRoleCredentials); s3Wrapper.UpdateClients(s3Client2, stsClient2); buckets = await s3Wrapper.ListMyBucketsAsync(); uiWrapper.DisplayTitle("List Amazon S3 buckets"); Console.WriteLine("This time we should have buckets to list."); if (buckets is not null) { buckets.ForEach(bucket => { Console.WriteLine($"{bucket.BucketName} created: {bucket.CreationDate}"); }); } uiWrapper.PressEnter(); // Now clean up all the resources used in the example. uiWrapper.DisplayTitle("Clean up resources"); Console.WriteLine("Thank you for watching. The IAM Basics demo is complete."); Console.WriteLine("Please wait while we clean up the resources we created."); await iamWrapper.DetachRolePolicyAsync(policy.Arn, roleName); await iamWrapper.DeletePolicyAsync(policy.Arn); await iamWrapper.DeleteRoleAsync(roleName); await iamWrapper.DeleteAccessKeyAsync(accessKeyId, userName); await iamWrapper.DeleteUserAsync(userName); uiWrapper.PressEnter(); Console.WriteLine("All done cleaning up our resources. Thank you for your patience."); } } namespace IamScenariosCommon; using System.Net; /// <summary> /// A class to perform Amazon Simple Storage Service (Amazon S3) actions for /// the IAM Basics scenario. /// </summary> public class S3Wrapper { private IAmazonS3 _s3Service; private IAmazonSecurityTokenService _stsService; /// <summary> /// Constructor for the S3Wrapper class. /// </summary> /// <param name="s3Service">An Amazon S3 client object.</param> /// <param name="stsService">An AWS Security Token Service (AWS STS) /// client object.</param> public S3Wrapper(IAmazonS3 s3Service, IAmazonSecurityTokenService stsService) { _s3Service = s3Service; _stsService = stsService; } /// <summary> /// Assumes an AWS Identity and Access Management (IAM) role that allows /// Amazon S3 access for the current session. /// </summary> /// <param name="roleSession">A string representing the current session.</param> /// <param name="roleToAssume">The name of the IAM role to assume.</param> /// <returns>Credentials for the newly assumed IAM role.</returns> public async Task<Credentials> AssumeS3RoleAsync(string roleSession, string roleToAssume) { // Create the request to use with the AssumeRoleAsync call. var request = new AssumeRoleRequest() { RoleSessionName = roleSession, RoleArn = roleToAssume, }; var response = await _stsService.AssumeRoleAsync(request); return response.Credentials; } /// <summary> /// Delete an S3 bucket. /// </summary> /// <param name="bucketName">Name of the S3 bucket to delete.</param> /// <returns>A Boolean value indicating the success of the action.</returns> public async Task<bool> DeleteBucketAsync(string bucketName) { var result = await _s3Service.DeleteBucketAsync(new DeleteBucketRequest { BucketName = bucketName }); return result.HttpStatusCode == HttpStatusCode.OK; } /// <summary> /// List the buckets that are owned by the user's account. /// </summary> /// <returns>Async Task.</returns> public async Task<List<S3Bucket>?> ListMyBucketsAsync() { try { // Get the list of buckets accessible by the new user. var response = await _s3Service.ListBucketsAsync(); return response.Buckets; } catch (AmazonS3Exception ex) { // Something else went wrong. Display the error message. Console.WriteLine($"Error: {ex.Message}"); return null; } } /// <summary> /// Create a new S3 bucket. /// </summary> /// <param name="bucketName">The name for the new bucket.</param> /// <returns>A Boolean value indicating whether the action completed /// successfully.</returns> public async Task<bool> PutBucketAsync(string bucketName) { var response = await _s3Service.PutBucketAsync(new PutBucketRequest { BucketName = bucketName }); return response.HttpStatusCode == HttpStatusCode.OK; } /// <summary> /// Update the client objects with new client objects. This is available /// because the scenario uses the methods of this class without and then /// with the proper permissions to list S3 buckets. /// </summary> /// <param name="s3Service">The Amazon S3 client object.</param> /// <param name="stsService">The AWS STS client object.</param> public void UpdateClients(IAmazonS3 s3Service, IAmazonSecurityTokenService stsService) { _s3Service = s3Service; _stsService = stsService; } } namespace IamScenariosCommon; public class UIWrapper { public readonly string SepBar = new('-', Console.WindowWidth); /// <summary> /// Show information about the IAM Groups scenario. /// </summary> public void DisplayGroupsOverview() { Console.Clear(); DisplayTitle("Welcome to the IAM Groups Demo"); Console.WriteLine("This example application does the following:"); Console.WriteLine("\t1. Creates an Amazon Identity and Access Management (IAM) group."); Console.WriteLine("\t2. Adds an IAM policy to the IAM group giving it full access to Amazon S3."); Console.WriteLine("\t3. Creates a new IAM user."); Console.WriteLine("\t4. Creates an IAM access key for the user."); Console.WriteLine("\t5. Adds the user to the IAM group."); Console.WriteLine("\t6. Lists the buckets on the account."); Console.WriteLine("\t7. Proves that the user has full Amazon S3 access by creating a bucket."); Console.WriteLine("\t8. List the buckets again to show the new bucket."); Console.WriteLine("\t9. Cleans up all the resources created."); } /// <summary> /// Show information about the IAM Basics scenario. /// </summary> public void DisplayBasicsOverview() { Console.Clear(); DisplayTitle("Welcome to IAM Basics"); Console.WriteLine("This example application does the following:"); Console.WriteLine("\t1. Creates a user with no permissions."); Console.WriteLine("\t2. Creates a role and policy that grant s3:ListAllMyBuckets permission."); Console.WriteLine("\t3. Grants the user permission to assume the role."); Console.WriteLine("\t4. Creates an S3 client object as the user and tries to list buckets (this will fail)."); Console.WriteLine("\t5. Gets temporary credentials by assuming the role."); Console.WriteLine("\t6. Creates a new S3 client object with the temporary credentials and lists the buckets (this will succeed)."); Console.WriteLine("\t7. Deletes all the resources."); } /// <summary> /// Display a message and wait until the user presses enter. /// </summary> public void PressEnter() { Console.Write("\nPress <Enter> to continue. "); _ = Console.ReadLine(); Console.WriteLine(); } /// <summary> /// Pad a string with spaces to center it on the console display. /// </summary> /// <param name="strToCenter">The string to be centered.</param> /// <returns>The padded string.</returns> public string CenterString(string strToCenter) { var padAmount = (Console.WindowWidth - strToCenter.Length) / 2; var leftPad = new string(' ', padAmount); return $"{leftPad}{strToCenter}"; } /// <summary> /// Display a line of hyphens, the centered text of the title, and another /// line of hyphens. /// </summary> /// <param name="strTitle">The string to be displayed.</param> public void DisplayTitle(string strTitle) { Console.WriteLine(SepBar); Console.WriteLine(CenterString(strTitle)); Console.WriteLine(SepBar); } /// <summary> /// Display a countdown and wait for a number of seconds. /// </summary> /// <param name="numSeconds">The number of seconds to wait.</param> public void WaitABit(int numSeconds, string msg) { Console.WriteLine(msg); // Wait for the requested number of seconds. for (int i = numSeconds; i > 0; i--) { System.Threading.Thread.Sleep(1000); Console.Write($"{i}..."); } PressEnter(); } }