2
0

agent.go 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. package aws
  2. import (
  3. "github.com/aws/aws-sdk-go/aws/session"
  4. "github.com/aws/aws-sdk-go/service/iam"
  5. "github.com/porter-dev/porter/cli/cmd/utils"
  6. "k8s.io/client-go/kubernetes"
  7. )
  8. type Agent struct {
  9. Session *session.Session
  10. IAMService *iam.IAM
  11. Clientset kubernetes.Interface
  12. }
  13. type PorterAWSCredentials struct {
  14. AWSAccessKeyID string `json:"aws_access_key_id"`
  15. AWSSecretAccessKey string `json:"aws_secret_access_key"`
  16. AWSClusterID string `json:"aws_cluster_id"`
  17. }
  18. func (a *Agent) CreateIAMKubernetesMapping(clusterIDGuess string) (*PorterAWSCredentials, error) {
  19. user, err := a.getIAMUserIfExists()
  20. if err != nil {
  21. return nil, err
  22. }
  23. var name string
  24. if user == nil {
  25. // (1) Create a new IAM user called porter-dashboard-[random_string], and attach the policy:
  26. name = "porter-dashboard-" + utils.StringWithCharset(6, "abcdefghijklmnopqrstuvwxyz1234567890")
  27. resp, err := a.IAMService.CreateUser(&iam.CreateUserInput{
  28. UserName: &name,
  29. })
  30. if err != nil {
  31. return nil, err
  32. }
  33. user = resp.User
  34. } else {
  35. name = *user.UserName
  36. }
  37. policyArn := "arn:aws:iam::aws:policy/AmazonEKSClusterPolicy"
  38. _, err = a.IAMService.AttachUserPolicy(&iam.AttachUserPolicyInput{
  39. PolicyArn: &policyArn,
  40. UserName: &name,
  41. })
  42. if err != nil {
  43. return nil, err
  44. }
  45. // (2) Create an access key for the porter-dashboard-[random_string] user and return the
  46. // access key and secret. Use the guessed cluster ID.
  47. resp, err := a.IAMService.CreateAccessKey(&iam.CreateAccessKeyInput{
  48. UserName: &name,
  49. })
  50. if err != nil {
  51. return nil, err
  52. }
  53. porterCreds := &PorterAWSCredentials{
  54. AWSAccessKeyID: *resp.AccessKey.AccessKeyId,
  55. AWSSecretAccessKey: *resp.AccessKey.SecretAccessKey,
  56. AWSClusterID: clusterIDGuess,
  57. }
  58. // (3) Use the eksctl authconfigmap package to map this user to a cluster identity.
  59. authCm, err := NewFromClientSet(a.Clientset)
  60. if err != nil {
  61. return nil, err
  62. }
  63. identity, err := NewIdentity(
  64. *user.Arn,
  65. "admin",
  66. []string{"system:masters"},
  67. )
  68. if err != nil {
  69. return nil, err
  70. }
  71. err = authCm.AddIdentity(identity)
  72. if err != nil {
  73. return nil, err
  74. }
  75. err = authCm.Save()
  76. if err != nil {
  77. return nil, err
  78. }
  79. return porterCreds, nil
  80. }
  81. // CreateIAMECRUser creates an IAM user if it does not exist, and attaches a ECR-read policy
  82. // to the user
  83. func (a *Agent) CreateIAMECRUser(region string) (*PorterAWSCredentials, error) {
  84. user, err := a.getIAMUserIfExists()
  85. if err != nil {
  86. return nil, err
  87. }
  88. var name string
  89. if user == nil {
  90. // (1) Create a new IAM user called porter-dashboard-[random_string], and attach the policy:
  91. //
  92. // arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly
  93. name = "porter-dashboard-" + utils.StringWithCharset(6, "abcdefghijklmnopqrstuvwxyz1234567890")
  94. resp, err := a.IAMService.CreateUser(&iam.CreateUserInput{
  95. UserName: &name,
  96. })
  97. if err != nil {
  98. return nil, err
  99. }
  100. user = resp.User
  101. } else {
  102. name = *user.UserName
  103. }
  104. policyArn := "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryFullAccess"
  105. _, err = a.IAMService.AttachUserPolicy(&iam.AttachUserPolicyInput{
  106. PolicyArn: &policyArn,
  107. UserName: &name,
  108. })
  109. if err != nil {
  110. return nil, err
  111. }
  112. // (2) Create an access key for the porter-dashboard-[random_string] user and return the
  113. // access key and secret. Use the guessed cluster ID.
  114. resp, err := a.IAMService.CreateAccessKey(&iam.CreateAccessKeyInput{
  115. UserName: &name,
  116. })
  117. if err != nil {
  118. return nil, err
  119. }
  120. porterCreds := &PorterAWSCredentials{
  121. AWSAccessKeyID: *resp.AccessKey.AccessKeyId,
  122. AWSSecretAccessKey: *resp.AccessKey.SecretAccessKey,
  123. }
  124. return porterCreds, nil
  125. }
  126. func (a *Agent) getIAMUserIfExists() (*iam.User, error) {
  127. // resp, err := a.IAMService.ListUsers(&iam.ListUsersInput{})
  128. // if err != nil {
  129. // return nil, err
  130. // }
  131. // re := regexp.MustCompile(`porter-dashboard-[a-z1-9]{6}`)
  132. // for _, user := range resp.Users {
  133. // if re.MatchString(*user.UserName) {
  134. // return user, nil
  135. // }
  136. // }
  137. return nil, nil
  138. }