/vendor/github.com/hashicorp/terraform/vendor/github.com/terraform-providers/terraform-provider-aws/aws/resource_aws_iam_policy.go

https://github.com/alibaba/terraform-provider · Go · 296 lines · 249 code · 38 blank · 9 comment · 65 complexity · c27aba3f3404a44b646b1f82a2854f66 MD5 · raw file

  1. package aws
  2. import (
  3. "fmt"
  4. "net/url"
  5. "regexp"
  6. "github.com/aws/aws-sdk-go/aws"
  7. "github.com/aws/aws-sdk-go/aws/awserr"
  8. "github.com/aws/aws-sdk-go/service/iam"
  9. "github.com/hashicorp/terraform/helper/resource"
  10. "github.com/hashicorp/terraform/helper/schema"
  11. )
  12. func resourceAwsIamPolicy() *schema.Resource {
  13. return &schema.Resource{
  14. Create: resourceAwsIamPolicyCreate,
  15. Read: resourceAwsIamPolicyRead,
  16. Update: resourceAwsIamPolicyUpdate,
  17. Delete: resourceAwsIamPolicyDelete,
  18. Importer: &schema.ResourceImporter{
  19. State: schema.ImportStatePassthrough,
  20. },
  21. Schema: map[string]*schema.Schema{
  22. "description": {
  23. Type: schema.TypeString,
  24. ForceNew: true,
  25. Optional: true,
  26. },
  27. "path": {
  28. Type: schema.TypeString,
  29. Optional: true,
  30. Default: "/",
  31. ForceNew: true,
  32. },
  33. "policy": {
  34. Type: schema.TypeString,
  35. Required: true,
  36. ValidateFunc: validateIAMPolicyJson,
  37. DiffSuppressFunc: suppressEquivalentAwsPolicyDiffs,
  38. },
  39. "name": {
  40. Type: schema.TypeString,
  41. Optional: true,
  42. Computed: true,
  43. ForceNew: true,
  44. ConflictsWith: []string{"name_prefix"},
  45. ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) {
  46. // https://github.com/boto/botocore/blob/2485f5c/botocore/data/iam/2010-05-08/service-2.json#L8329-L8334
  47. value := v.(string)
  48. if len(value) > 128 {
  49. errors = append(errors, fmt.Errorf(
  50. "%q cannot be longer than 128 characters", k))
  51. }
  52. if !regexp.MustCompile("^[\\w+=,.@-]*$").MatchString(value) {
  53. errors = append(errors, fmt.Errorf(
  54. "%q must match [\\w+=,.@-]", k))
  55. }
  56. return
  57. },
  58. },
  59. "name_prefix": {
  60. Type: schema.TypeString,
  61. Optional: true,
  62. ForceNew: true,
  63. ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) {
  64. // https://github.com/boto/botocore/blob/2485f5c/botocore/data/iam/2010-05-08/service-2.json#L8329-L8334
  65. value := v.(string)
  66. if len(value) > 96 {
  67. errors = append(errors, fmt.Errorf(
  68. "%q cannot be longer than 96 characters, name is limited to 128", k))
  69. }
  70. if !regexp.MustCompile("^[\\w+=,.@-]*$").MatchString(value) {
  71. errors = append(errors, fmt.Errorf(
  72. "%q must match [\\w+=,.@-]", k))
  73. }
  74. return
  75. },
  76. },
  77. "arn": {
  78. Type: schema.TypeString,
  79. Computed: true,
  80. },
  81. },
  82. }
  83. }
  84. func resourceAwsIamPolicyCreate(d *schema.ResourceData, meta interface{}) error {
  85. iamconn := meta.(*AWSClient).iamconn
  86. var name string
  87. if v, ok := d.GetOk("name"); ok {
  88. name = v.(string)
  89. } else if v, ok := d.GetOk("name_prefix"); ok {
  90. name = resource.PrefixedUniqueId(v.(string))
  91. } else {
  92. name = resource.UniqueId()
  93. }
  94. request := &iam.CreatePolicyInput{
  95. Description: aws.String(d.Get("description").(string)),
  96. Path: aws.String(d.Get("path").(string)),
  97. PolicyDocument: aws.String(d.Get("policy").(string)),
  98. PolicyName: aws.String(name),
  99. }
  100. response, err := iamconn.CreatePolicy(request)
  101. if err != nil {
  102. return fmt.Errorf("Error creating IAM policy %s: %s", name, err)
  103. }
  104. return readIamPolicy(d, response.Policy)
  105. }
  106. func resourceAwsIamPolicyRead(d *schema.ResourceData, meta interface{}) error {
  107. iamconn := meta.(*AWSClient).iamconn
  108. getPolicyRequest := &iam.GetPolicyInput{
  109. PolicyArn: aws.String(d.Id()),
  110. }
  111. getPolicyResponse, err := iamconn.GetPolicy(getPolicyRequest)
  112. if err != nil {
  113. if iamerr, ok := err.(awserr.Error); ok && iamerr.Code() == "NoSuchEntity" {
  114. d.SetId("")
  115. return nil
  116. }
  117. return fmt.Errorf("Error reading IAM policy %s: %s", d.Id(), err)
  118. }
  119. getPolicyVersionRequest := &iam.GetPolicyVersionInput{
  120. PolicyArn: aws.String(d.Id()),
  121. VersionId: getPolicyResponse.Policy.DefaultVersionId,
  122. }
  123. getPolicyVersionResponse, err := iamconn.GetPolicyVersion(getPolicyVersionRequest)
  124. if err != nil {
  125. if iamerr, ok := err.(awserr.Error); ok && iamerr.Code() == "NoSuchEntity" {
  126. d.SetId("")
  127. return nil
  128. }
  129. return fmt.Errorf("Error reading IAM policy version %s: %s", d.Id(), err)
  130. }
  131. policy, err := url.QueryUnescape(*getPolicyVersionResponse.PolicyVersion.Document)
  132. if err != nil {
  133. return err
  134. }
  135. if err := d.Set("policy", policy); err != nil {
  136. return err
  137. }
  138. return readIamPolicy(d, getPolicyResponse.Policy)
  139. }
  140. func resourceAwsIamPolicyUpdate(d *schema.ResourceData, meta interface{}) error {
  141. iamconn := meta.(*AWSClient).iamconn
  142. if err := iamPolicyPruneVersions(d.Id(), iamconn); err != nil {
  143. return err
  144. }
  145. if !d.HasChange("policy") {
  146. return nil
  147. }
  148. request := &iam.CreatePolicyVersionInput{
  149. PolicyArn: aws.String(d.Id()),
  150. PolicyDocument: aws.String(d.Get("policy").(string)),
  151. SetAsDefault: aws.Bool(true),
  152. }
  153. if _, err := iamconn.CreatePolicyVersion(request); err != nil {
  154. return fmt.Errorf("Error updating IAM policy %s: %s", d.Id(), err)
  155. }
  156. return nil
  157. }
  158. func resourceAwsIamPolicyDelete(d *schema.ResourceData, meta interface{}) error {
  159. iamconn := meta.(*AWSClient).iamconn
  160. if err := iamPolicyDeleteNondefaultVersions(d.Id(), iamconn); err != nil {
  161. return err
  162. }
  163. request := &iam.DeletePolicyInput{
  164. PolicyArn: aws.String(d.Id()),
  165. }
  166. _, err := iamconn.DeletePolicy(request)
  167. if err != nil {
  168. if iamerr, ok := err.(awserr.Error); ok && iamerr.Code() == "NoSuchEntity" {
  169. return nil
  170. }
  171. return fmt.Errorf("Error deleting IAM policy %s: %#v", d.Id(), err)
  172. }
  173. return nil
  174. }
  175. // iamPolicyPruneVersions deletes the oldest versions.
  176. //
  177. // Old versions are deleted until there are 4 or less remaining, which means at
  178. // least one more can be created before hitting the maximum of 5.
  179. //
  180. // The default version is never deleted.
  181. func iamPolicyPruneVersions(arn string, iamconn *iam.IAM) error {
  182. versions, err := iamPolicyListVersions(arn, iamconn)
  183. if err != nil {
  184. return err
  185. }
  186. if len(versions) < 5 {
  187. return nil
  188. }
  189. var oldestVersion *iam.PolicyVersion
  190. for _, version := range versions {
  191. if *version.IsDefaultVersion {
  192. continue
  193. }
  194. if oldestVersion == nil ||
  195. version.CreateDate.Before(*oldestVersion.CreateDate) {
  196. oldestVersion = version
  197. }
  198. }
  199. if err := iamPolicyDeleteVersion(arn, *oldestVersion.VersionId, iamconn); err != nil {
  200. return err
  201. }
  202. return nil
  203. }
  204. func iamPolicyDeleteNondefaultVersions(arn string, iamconn *iam.IAM) error {
  205. versions, err := iamPolicyListVersions(arn, iamconn)
  206. if err != nil {
  207. return err
  208. }
  209. for _, version := range versions {
  210. if *version.IsDefaultVersion {
  211. continue
  212. }
  213. if err := iamPolicyDeleteVersion(arn, *version.VersionId, iamconn); err != nil {
  214. return err
  215. }
  216. }
  217. return nil
  218. }
  219. func iamPolicyDeleteVersion(arn, versionID string, iamconn *iam.IAM) error {
  220. request := &iam.DeletePolicyVersionInput{
  221. PolicyArn: aws.String(arn),
  222. VersionId: aws.String(versionID),
  223. }
  224. _, err := iamconn.DeletePolicyVersion(request)
  225. if err != nil {
  226. return fmt.Errorf("Error deleting version %s from IAM policy %s: %s", versionID, arn, err)
  227. }
  228. return nil
  229. }
  230. func iamPolicyListVersions(arn string, iamconn *iam.IAM) ([]*iam.PolicyVersion, error) {
  231. request := &iam.ListPolicyVersionsInput{
  232. PolicyArn: aws.String(arn),
  233. }
  234. response, err := iamconn.ListPolicyVersions(request)
  235. if err != nil {
  236. return nil, fmt.Errorf("Error listing versions for IAM policy %s: %s", arn, err)
  237. }
  238. return response.Versions, nil
  239. }
  240. func readIamPolicy(d *schema.ResourceData, policy *iam.Policy) error {
  241. d.SetId(*policy.Arn)
  242. if policy.Description != nil {
  243. // the description isn't present in the response to CreatePolicy.
  244. if err := d.Set("description", policy.Description); err != nil {
  245. return err
  246. }
  247. }
  248. if err := d.Set("path", policy.Path); err != nil {
  249. return err
  250. }
  251. if err := d.Set("name", policy.PolicyName); err != nil {
  252. return err
  253. }
  254. if err := d.Set("arn", policy.Arn); err != nil {
  255. return err
  256. }
  257. return nil
  258. }