IAM 使用 的範例 AWS SDK for .NET - AWS SDK for .NET

本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。

IAM 使用 的範例 AWS SDK for .NET

下列程式碼範例示範如何搭配 AWS SDK for .NET 使用 來執行動作和實作常見案例IAM。

基本知識是程式碼範例,可示範如何在 服務內執行基本操作。

Actions 是大型程式的程式碼摘錄,必須在內容中執行。雖然動作會示範如何呼叫個別服務函數,但您可以在相關案例中查看內容中的動作。

案例是程式碼範例,示範如何透過呼叫服務內的多個函數或與其他 結合來完成特定任務 AWS 服務。

每個範例都包含完整原始程式碼的連結,您可以在其中找到如何在內容中設定和執行程式碼的指示。

開始使用

下列程式碼範例說明如何開始使用 IAM。

AWS SDK for .NET
注意

還有更多 。 GitHub尋找完整範例,並了解如何在 AWS 程式碼範例儲存庫中設定和執行。

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詳細資訊,請參閱 參考 ListPolicies中的 。 AWS SDK for .NET API

基本概念

下列程式碼範例示範如何建立使用者並擔任角色。

警告

為了避免安全風險,在開發專用軟體或使用真實資料時,請勿使用IAM使用者進行身分驗證。相反地,搭配使用聯合功能和身分提供者,例如 AWS IAM Identity Center

  • 建立沒有許可的使用者。

  • 建立一個可授予許可的角色,以列出帳戶的 Amazon S3 儲存貯體。

  • 新增政策,讓使用者擔任該角色。

  • 使用暫時憑證,擔任角色並列出 Amazon S3 儲存貯體,然後清理資源。

AWS SDK for .NET
注意

還有更多 。 GitHub尋找完整範例,並了解如何在 AWS 程式碼範例儲存庫中設定和執行。

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(); } }

動作

下列程式碼範例示範如何使用 AddUserToGroup

AWS SDK for .NET
注意

還有更多 。 GitHub尋找完整範例,並了解如何在 AWS 程式碼範例儲存庫中設定和執行。

/// <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詳細資訊,請參閱 參考 AddUserToGroup中的 。 AWS SDK for .NET API

下列程式碼範例示範如何使用 AttachRolePolicy

AWS SDK for .NET
注意

還有更多 。 GitHub尋找完整範例,並了解如何在 AWS 程式碼範例儲存庫中設定和執行。

/// <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詳細資訊,請參閱 參考 AttachRolePolicy中的 。 AWS SDK for .NET API

下列程式碼範例示範如何使用 CreateAccessKey

AWS SDK for .NET
注意

還有更多 。 GitHub尋找完整範例,並了解如何在 AWS 程式碼範例儲存庫中設定和執行。

/// <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詳細資訊,請參閱 參考 CreateAccessKey中的 。 AWS SDK for .NET API

下列程式碼範例示範如何使用 CreateGroup

AWS SDK for .NET
注意

還有更多 。 GitHub尋找完整範例,並了解如何在 AWS 程式碼範例儲存庫中設定和執行。

/// <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詳細資訊,請參閱 參考 CreateGroup中的 。 AWS SDK for .NET API

下列程式碼範例示範如何使用 CreateInstanceProfile

AWS SDK for .NET
注意

還有更多 。 GitHub尋找完整範例,並了解如何在 AWS 程式碼範例儲存庫中設定和執行。

/// <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; }

下列程式碼範例示範如何使用 CreatePolicy

AWS SDK for .NET
注意

還有更多 。 GitHub尋找完整範例,並了解如何在 AWS 程式碼範例儲存庫中設定和執行。

/// <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詳細資訊,請參閱 參考 CreatePolicy中的 。 AWS SDK for .NET API

下列程式碼範例示範如何使用 CreateRole

AWS SDK for .NET
注意

還有更多 。 GitHub尋找完整範例,並了解如何在 AWS 程式碼範例儲存庫中設定和執行。

/// <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詳細資訊,請參閱 參考 CreateRole中的 。 AWS SDK for .NET API

下列程式碼範例示範如何使用 CreateServiceLinkedRole

AWS SDK for .NET
注意

還有更多 。 GitHub尋找完整範例,並了解如何在 AWS 程式碼範例儲存庫中設定和執行。

/// <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; }

下列程式碼範例示範如何使用 CreateUser

AWS SDK for .NET
注意

還有更多 。 GitHub尋找完整範例,並了解如何在 AWS 程式碼範例儲存庫中設定和執行。

/// <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詳細資訊,請參閱 參考 CreateUser中的 。 AWS SDK for .NET API

下列程式碼範例示範如何使用 DeleteAccessKey

AWS SDK for .NET
注意

還有更多 。 GitHub尋找完整範例,並了解如何在 AWS 程式碼範例儲存庫中設定和執行。

/// <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詳細資訊,請參閱 參考 DeleteAccessKey中的 。 AWS SDK for .NET API

下列程式碼範例示範如何使用 DeleteGroup

AWS SDK for .NET
注意

還有更多 。 GitHub尋找完整範例,並了解如何在 AWS 程式碼範例儲存庫中設定和執行。

/// <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詳細資訊,請參閱 參考 DeleteGroup中的 。 AWS SDK for .NET API

下列程式碼範例示範如何使用 DeleteGroupPolicy

AWS SDK for .NET
注意

還有更多 。 GitHub尋找完整範例,並了解如何在 AWS 程式碼範例儲存庫中設定和執行。

/// <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詳細資訊,請參閱 參考 DeleteGroupPolicy中的 。 AWS SDK for .NET API

下列程式碼範例示範如何使用 DeleteInstanceProfile

AWS SDK for .NET
注意

還有更多 。 GitHub尋找完整範例,並了解如何在 AWS 程式碼範例儲存庫中設定和執行。

/// <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."); } }

下列程式碼範例示範如何使用 DeletePolicy

AWS SDK for .NET
注意

還有更多 。 GitHub尋找完整範例,並了解如何在 AWS 程式碼範例儲存庫中設定和執行。

/// <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詳細資訊,請參閱 參考 DeletePolicy中的 。 AWS SDK for .NET API

下列程式碼範例示範如何使用 DeleteRole

AWS SDK for .NET
注意

還有更多 。 GitHub尋找完整範例,並了解如何在 AWS 程式碼範例儲存庫中設定和執行。

/// <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詳細資訊,請參閱 參考 DeleteRole中的 。 AWS SDK for .NET API

下列程式碼範例示範如何使用 DeleteRolePolicy

AWS SDK for .NET
注意

還有更多 。 GitHub尋找完整範例,並了解如何在 AWS 程式碼範例儲存庫中設定和執行。

/// <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詳細資訊,請參閱 參考 DeleteRolePolicy中的 。 AWS SDK for .NET API

下列程式碼範例示範如何使用 DeleteUser

AWS SDK for .NET
注意

還有更多 。 GitHub尋找完整範例,並了解如何在 AWS 程式碼範例儲存庫中設定和執行。

/// <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詳細資訊,請參閱 參考 DeleteUser中的 。 AWS SDK for .NET API

下列程式碼範例示範如何使用 DeleteUserPolicy

AWS SDK for .NET
注意

還有更多 。 GitHub尋找完整範例,並了解如何在 AWS 程式碼範例儲存庫中設定和執行。

/// <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詳細資訊,請參閱 參考 DeleteUserPolicy中的 。 AWS SDK for .NET API

下列程式碼範例示範如何使用 DetachRolePolicy

AWS SDK for .NET
注意

還有更多 。 GitHub尋找完整範例,並了解如何在 AWS 程式碼範例儲存庫中設定和執行。

/// <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詳細資訊,請參閱 參考 DetachRolePolicy中的 。 AWS SDK for .NET API

下列程式碼範例示範如何使用 GetAccountPasswordPolicy

AWS SDK for .NET
注意

還有更多 。 GitHub尋找完整範例,並了解如何在 AWS 程式碼範例儲存庫中設定和執行。

/// <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; }

下列程式碼範例示範如何使用 GetPolicy

AWS SDK for .NET
注意

還有更多 。 GitHub尋找完整範例,並了解如何在 AWS 程式碼範例儲存庫中設定和執行。

/// <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詳細資訊,請參閱 參考 GetPolicy中的 。 AWS SDK for .NET API

下列程式碼範例示範如何使用 GetRole

AWS SDK for .NET
注意

還有更多 。 GitHub尋找完整範例,並了解如何在 AWS 程式碼範例儲存庫中設定和執行。

/// <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詳細資訊,請參閱 參考 GetRole中的 。 AWS SDK for .NET API

下列程式碼範例示範如何使用 GetUser

AWS SDK for .NET
注意

還有更多 。 GitHub尋找完整範例,並了解如何在 AWS 程式碼範例儲存庫中設定和執行。

/// <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詳細資訊,請參閱 參考 GetUser中的 。 AWS SDK for .NET API

下列程式碼範例示範如何使用 ListAttachedRolePolicies

AWS SDK for .NET
注意

還有更多 。 GitHub尋找完整範例,並了解如何在 AWS 程式碼範例儲存庫中設定和執行。

/// <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; }

下列程式碼範例示範如何使用 ListGroups

AWS SDK for .NET
注意

還有更多 。 GitHub尋找完整範例,並了解如何在 AWS 程式碼範例儲存庫中設定和執行。

/// <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詳細資訊,請參閱 參考 ListGroups中的 。 AWS SDK for .NET API

下列程式碼範例示範如何使用 ListPolicies

AWS SDK for .NET
注意

還有更多 。 GitHub尋找完整範例,並了解如何在 AWS 程式碼範例儲存庫中設定和執行。

/// <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詳細資訊,請參閱 參考 ListPolicies中的 。 AWS SDK for .NET API

下列程式碼範例示範如何使用 ListRolePolicies

AWS SDK for .NET
注意

還有更多 。 GitHub尋找完整範例,並了解如何在 AWS 程式碼範例儲存庫中設定和執行。

/// <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詳細資訊,請參閱 參考 ListRolePolicies中的 。 AWS SDK for .NET API

下列程式碼範例示範如何使用 ListRoles

AWS SDK for .NET
注意

還有更多 。 GitHub尋找完整範例,並了解如何在 AWS 程式碼範例儲存庫中設定和執行。

/// <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詳細資訊,請參閱 參考 ListRoles中的 。 AWS SDK for .NET API

下列程式碼範例示範如何使用 ListSAMLProviders

AWS SDK for .NET
注意

還有更多 。 GitHub尋找完整範例,並了解如何在 AWS 程式碼範例儲存庫中設定和執行。

/// <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詳細資訊,請參閱AWS SDK for .NET API參考 中的 ListSAMLProviders

下列程式碼範例示範如何使用 ListUsers

AWS SDK for .NET
注意

還有更多 。 GitHub尋找完整範例,並了解如何在 AWS 程式碼範例儲存庫中設定和執行。

/// <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詳細資訊,請參閱 參考 ListUsers中的 。 AWS SDK for .NET API

下列程式碼範例示範如何使用 PutGroupPolicy

AWS SDK for .NET
注意

還有更多 。 GitHub尋找完整範例,並了解如何在 AWS 程式碼範例儲存庫中設定和執行。

/// <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詳細資訊,請參閱 參考 PutGroupPolicy中的 。 AWS SDK for .NET API

下列程式碼範例示範如何使用 PutRolePolicy

AWS SDK for .NET
注意

還有更多 。 GitHub尋找完整範例,並了解如何在 AWS 程式碼範例儲存庫中設定和執行。

/// <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詳細資訊,請參閱 參考 PutRolePolicy中的 。 AWS SDK for .NET API

下列程式碼範例示範如何使用 RemoveUserFromGroup

AWS SDK for .NET
注意

還有更多 。 GitHub尋找完整範例,並了解如何在 AWS 程式碼範例儲存庫中設定和執行。

/// <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; }

案例

下列程式碼範例會示範如何建立負載平衡的 Web 服務,以傳回書籍、影片和歌曲建議。此範例顯示服務如何回應失故障,以及如何在發生故障時重組服務以提高復原能力。

  • 使用 Amazon EC2 Auto Scaling 群組,根據啟動範本建立 Amazon Elastic Compute Cloud (Amazon EC2) 執行個體,並保留指定範圍內的執行個體數量。

  • 使用 Elastic Load Balancing 處理和分發HTTP請求。

  • 監控 Auto Scaling 群組中執行個體的運作狀態,並且只將請求轉送給運作良好的執行個體。

  • 在每個EC2執行個體上執行 Python Web 伺服器來處理HTTP請求。Web 伺服器會回應建議和運作狀態檢查。

  • 使用 Amazon DynamoDB 資料表模擬建議服務。

  • 透過更新 AWS Systems Manager 參數來控制 Web 伺服器對請求和運作狀態檢查的回應。

AWS SDK for .NET
注意

還有更多 。 GitHub尋找完整範例,並了解如何在 AWS 程式碼範例儲存庫中設定和執行。

在命令提示中執行互動式案例。

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; }

建立包裝 Auto Scaling 和 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 ILogger<AutoScalerWrapper> _logger; 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, ILogger<AutoScalerWrapper> logger) { _amazonAutoScaling = amazonAutoScaling; _amazonEc2 = amazonEc2; _amazonSsm = amazonSsm; _amazonIam = amazonIam; _logger = logger; 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) { try { 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; } catch (AmazonEC2Exception ec2Exception) { if (ec2Exception.ErrorCode == "InvalidLaunchTemplateName.AlreadyExistsException") { _logger.LogError($"Could not create the template, the name {_launchTemplateName} already exists. " + $"Please try again with a unique name."); } throw; } catch (Exception ex) { _logger.LogError($"An error occurred while creating the template.: {ex.Message}"); throw; } } /// <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() { try { var zoneResponse = await _amazonEc2.DescribeAvailabilityZonesAsync( new DescribeAvailabilityZonesRequest()); return zoneResponse.AvailabilityZones.Select(z => z.ZoneName).ToList(); } catch (AmazonEC2Exception ec2Exception) { _logger.LogError($"An Amazon EC2 error occurred while listing availability zones.: {ec2Exception.Message}"); throw; } catch (Exception ex) { _logger.LogError($"An error occurred while listing availability zones.: {ex.Message}"); throw; } } /// <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() { try { 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]; } catch (AmazonEC2Exception ec2Exception) { if (ec2Exception.ErrorCode == "UnauthorizedOperation") { _logger.LogError(ec2Exception, $"You do not have the necessary permissions to describe VPCs."); } throw; } catch (Exception ex) { _logger.LogError(ex, $"An error occurred while describing the vpcs.: {ex.Message}"); throw; } } /// <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) { try { 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; } catch (AmazonEC2Exception ec2Exception) { if (ec2Exception.ErrorCode == "InvalidVpcID.NotFound") { _logger.LogError(ec2Exception, $"The specified VPC ID {vpcId} does not exist."); } throw; } catch (Exception ex) { _logger.LogError(ex, $"An error occurred while describing the subnets.: {ex.Message}"); throw; } } /// <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 (AmazonEC2Exception ec2Exception) { if (ec2Exception.ErrorCode == "InvalidLaunchTemplateName.NotFoundException") { _logger.LogError( $"Could not delete the template, the name {_launchTemplateName} was not found."); } throw; } catch (Exception ex) { _logger.LogError($"An error occurred while deleting the template.: {ex.Message}"); throw; } } /// <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) { try { 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]; } catch (AmazonEC2Exception ec2Exception) { if (ec2Exception.ErrorCode == "InvalidInstanceID.NotFound") { _logger.LogError(ec2Exception, $"Instance {instanceId} not found"); } throw; } catch (Exception ex) { _logger.LogError(ex, $"An error occurred while creating the template.: {ex.Message}"); throw; } } /// <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) { try { await _amazonEc2.ReplaceIamInstanceProfileAssociationAsync( new ReplaceIamInstanceProfileAssociationRequest() { AssociationId = associationId, IamInstanceProfile = new IamInstanceProfileSpecification() { Name = credsProfileName } }); // Allow time before resetting. Thread.Sleep(25000); await _amazonEc2.RebootInstancesAsync( new RebootInstancesRequest(new List<string>() { instanceId })); Thread.Sleep(25000); var instanceReady = false; var retries = 5; while (retries-- > 0 && !instanceReady) { 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("Waiting for instance to be running."); await WaitForInstanceState(instanceId, InstanceStateName.Running); Console.WriteLine("Instance ready."); 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}"); } catch (AmazonEC2Exception ec2Exception) { if (ec2Exception.ErrorCode == "InvalidInstanceID.NotFound") { _logger.LogError(ec2Exception, $"Instance {instanceId} not found"); } throw; } catch (Exception ex) { _logger.LogError(ex, $"An error occurred while replacing the template.: {ex.Message}"); throw; } } /// <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> /// Wait until an EC2 instance is in a specified state. /// </summary> /// <param name="instanceId">The instance Id.</param> /// <param name="stateName">The state to wait for.</param> /// <returns>A Boolean value indicating the success of the action.</returns> public async Task<bool> WaitForInstanceState(string instanceId, InstanceStateName stateName) { var request = new DescribeInstancesRequest { InstanceIds = new List<string> { instanceId } }; // Wait until the instance is in the specified state. var hasState = false; do { // Wait 5 seconds. Thread.Sleep(5000); // Check for the desired state. var response = await _amazonEc2.DescribeInstancesAsync(request); var instance = response.Reservations[0].Instances[0]; hasState = instance.State.Name == stateName; Console.Write(". "); } while (!hasState); return hasState; } }

建立包裝 Elastic Load Balancing 動作的類別。

/// <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 的許可,然後清理資源。

AWS SDK for .NET
注意

還有更多 。 GitHub尋找完整範例,並了解如何在 AWS 程式碼範例儲存庫中設定和執行。

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(); } }