You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

644 lines
17 KiB

  1. // The iam package provides types and functions for interaction with the AWS
  2. // Identity and Access Management (IAM) service.
  3. package iam
  4. import (
  5. "encoding/xml"
  6. "net/http"
  7. "net/url"
  8. "strconv"
  9. "strings"
  10. "time"
  11. "github.com/goamz/goamz/aws"
  12. )
  13. // The IAM type encapsulates operations operations with the IAM endpoint.
  14. type IAM struct {
  15. aws.Auth
  16. aws.Region
  17. httpClient *http.Client
  18. }
  19. // New creates a new IAM instance.
  20. func New(auth aws.Auth, region aws.Region) *IAM {
  21. return NewWithClient(auth, region, aws.RetryingClient)
  22. }
  23. func NewWithClient(auth aws.Auth, region aws.Region, httpClient *http.Client) *IAM {
  24. return &IAM{auth, region, httpClient}
  25. }
  26. func (iam *IAM) query(params map[string]string, resp interface{}) error {
  27. params["Version"] = "2010-05-08"
  28. params["Timestamp"] = time.Now().In(time.UTC).Format(time.RFC3339)
  29. endpoint, err := url.Parse(iam.IAMEndpoint)
  30. if err != nil {
  31. return err
  32. }
  33. sign(iam.Auth, "GET", "/", params, endpoint.Host)
  34. endpoint.RawQuery = multimap(params).Encode()
  35. r, err := iam.httpClient.Get(endpoint.String())
  36. if err != nil {
  37. return err
  38. }
  39. defer r.Body.Close()
  40. if r.StatusCode > 200 {
  41. return buildError(r)
  42. }
  43. return xml.NewDecoder(r.Body).Decode(resp)
  44. }
  45. func (iam *IAM) postQuery(params map[string]string, resp interface{}) error {
  46. endpoint, err := url.Parse(iam.IAMEndpoint)
  47. if err != nil {
  48. return err
  49. }
  50. params["Version"] = "2010-05-08"
  51. params["Timestamp"] = time.Now().In(time.UTC).Format(time.RFC3339)
  52. sign(iam.Auth, "POST", "/", params, endpoint.Host)
  53. encoded := multimap(params).Encode()
  54. body := strings.NewReader(encoded)
  55. req, err := http.NewRequest("POST", endpoint.String(), body)
  56. if err != nil {
  57. return err
  58. }
  59. req.Header.Set("Host", endpoint.Host)
  60. req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
  61. req.Header.Set("Content-Length", strconv.Itoa(len(encoded)))
  62. r, err := http.DefaultClient.Do(req)
  63. if err != nil {
  64. return err
  65. }
  66. defer r.Body.Close()
  67. if r.StatusCode > 200 {
  68. return buildError(r)
  69. }
  70. return xml.NewDecoder(r.Body).Decode(resp)
  71. }
  72. func buildError(r *http.Response) error {
  73. var (
  74. err Error
  75. errors xmlErrors
  76. )
  77. xml.NewDecoder(r.Body).Decode(&errors)
  78. if len(errors.Errors) > 0 {
  79. err = errors.Errors[0]
  80. }
  81. err.StatusCode = r.StatusCode
  82. if err.Message == "" {
  83. err.Message = r.Status
  84. }
  85. return &err
  86. }
  87. func multimap(p map[string]string) url.Values {
  88. q := make(url.Values, len(p))
  89. for k, v := range p {
  90. q[k] = []string{v}
  91. }
  92. return q
  93. }
  94. // Response to a CreateUser request.
  95. //
  96. // See http://goo.gl/JS9Gz for more details.
  97. type CreateUserResp struct {
  98. RequestId string `xml:"ResponseMetadata>RequestId"`
  99. User User `xml:"CreateUserResult>User"`
  100. }
  101. // User encapsulates a user managed by IAM.
  102. //
  103. // See http://goo.gl/BwIQ3 for more details.
  104. type User struct {
  105. Arn string
  106. Path string
  107. Id string `xml:"UserId"`
  108. Name string `xml:"UserName"`
  109. }
  110. // CreateUser creates a new user in IAM.
  111. //
  112. // See http://goo.gl/JS9Gz for more details.
  113. func (iam *IAM) CreateUser(name, path string) (*CreateUserResp, error) {
  114. params := map[string]string{
  115. "Action": "CreateUser",
  116. "Path": path,
  117. "UserName": name,
  118. }
  119. resp := new(CreateUserResp)
  120. if err := iam.query(params, resp); err != nil {
  121. return nil, err
  122. }
  123. return resp, nil
  124. }
  125. // Response for GetUser requests.
  126. //
  127. // See http://goo.gl/ZnzRN for more details.
  128. type GetUserResp struct {
  129. RequestId string `xml:"ResponseMetadata>RequestId"`
  130. User User `xml:"GetUserResult>User"`
  131. }
  132. // GetUser gets a user from IAM.
  133. //
  134. // See http://goo.gl/ZnzRN for more details.
  135. func (iam *IAM) GetUser(name string) (*GetUserResp, error) {
  136. params := map[string]string{
  137. "Action": "GetUser",
  138. "UserName": name,
  139. }
  140. resp := new(GetUserResp)
  141. if err := iam.query(params, resp); err != nil {
  142. return nil, err
  143. }
  144. return resp, nil
  145. }
  146. // DeleteUser deletes a user from IAM.
  147. //
  148. // See http://goo.gl/jBuCG for more details.
  149. func (iam *IAM) DeleteUser(name string) (*SimpleResp, error) {
  150. params := map[string]string{
  151. "Action": "DeleteUser",
  152. "UserName": name,
  153. }
  154. resp := new(SimpleResp)
  155. if err := iam.query(params, resp); err != nil {
  156. return nil, err
  157. }
  158. return resp, nil
  159. }
  160. // Response to a CreateGroup request.
  161. //
  162. // See http://goo.gl/n7NNQ for more details.
  163. type CreateGroupResp struct {
  164. Group Group `xml:"CreateGroupResult>Group"`
  165. RequestId string `xml:"ResponseMetadata>RequestId"`
  166. }
  167. // Group encapsulates a group managed by IAM.
  168. //
  169. // See http://goo.gl/ae7Vs for more details.
  170. type Group struct {
  171. Arn string
  172. Id string `xml:"GroupId"`
  173. Name string `xml:"GroupName"`
  174. Path string
  175. }
  176. // CreateGroup creates a new group in IAM.
  177. //
  178. // The path parameter can be used to identify which division or part of the
  179. // organization the user belongs to.
  180. //
  181. // If path is unset ("") it defaults to "/".
  182. //
  183. // See http://goo.gl/n7NNQ for more details.
  184. func (iam *IAM) CreateGroup(name string, path string) (*CreateGroupResp, error) {
  185. params := map[string]string{
  186. "Action": "CreateGroup",
  187. "GroupName": name,
  188. }
  189. if path != "" {
  190. params["Path"] = path
  191. }
  192. resp := new(CreateGroupResp)
  193. if err := iam.query(params, resp); err != nil {
  194. return nil, err
  195. }
  196. return resp, nil
  197. }
  198. // Response to a ListGroups request.
  199. //
  200. // See http://goo.gl/W2TRj for more details.
  201. type GroupsResp struct {
  202. Groups []Group `xml:"ListGroupsResult>Groups>member"`
  203. RequestId string `xml:"ResponseMetadata>RequestId"`
  204. }
  205. // Groups list the groups that have the specified path prefix.
  206. //
  207. // The parameter pathPrefix is optional. If pathPrefix is "", all groups are
  208. // returned.
  209. //
  210. // See http://goo.gl/W2TRj for more details.
  211. func (iam *IAM) Groups(pathPrefix string) (*GroupsResp, error) {
  212. params := map[string]string{
  213. "Action": "ListGroups",
  214. }
  215. if pathPrefix != "" {
  216. params["PathPrefix"] = pathPrefix
  217. }
  218. resp := new(GroupsResp)
  219. if err := iam.query(params, resp); err != nil {
  220. return nil, err
  221. }
  222. return resp, nil
  223. }
  224. // DeleteGroup deletes a group from IAM.
  225. //
  226. // See http://goo.gl/d5i2i for more details.
  227. func (iam *IAM) DeleteGroup(name string) (*SimpleResp, error) {
  228. params := map[string]string{
  229. "Action": "DeleteGroup",
  230. "GroupName": name,
  231. }
  232. resp := new(SimpleResp)
  233. if err := iam.query(params, resp); err != nil {
  234. return nil, err
  235. }
  236. return resp, nil
  237. }
  238. // Response to a CreateAccessKey request.
  239. //
  240. // See http://goo.gl/L46Py for more details.
  241. type CreateAccessKeyResp struct {
  242. RequestId string `xml:"ResponseMetadata>RequestId"`
  243. AccessKey AccessKey `xml:"CreateAccessKeyResult>AccessKey"`
  244. }
  245. // AccessKey encapsulates an access key generated for a user.
  246. //
  247. // See http://goo.gl/LHgZR for more details.
  248. type AccessKey struct {
  249. UserName string
  250. Id string `xml:"AccessKeyId"`
  251. Secret string `xml:"SecretAccessKey,omitempty"`
  252. Status string
  253. }
  254. // CreateAccessKey creates a new access key in IAM.
  255. //
  256. // See http://goo.gl/L46Py for more details.
  257. func (iam *IAM) CreateAccessKey(userName string) (*CreateAccessKeyResp, error) {
  258. params := map[string]string{
  259. "Action": "CreateAccessKey",
  260. "UserName": userName,
  261. }
  262. resp := new(CreateAccessKeyResp)
  263. if err := iam.query(params, resp); err != nil {
  264. return nil, err
  265. }
  266. return resp, nil
  267. }
  268. // Response to AccessKeys request.
  269. //
  270. // See http://goo.gl/Vjozx for more details.
  271. type AccessKeysResp struct {
  272. RequestId string `xml:"ResponseMetadata>RequestId"`
  273. AccessKeys []AccessKey `xml:"ListAccessKeysResult>AccessKeyMetadata>member"`
  274. }
  275. // AccessKeys lists all acccess keys associated with a user.
  276. //
  277. // The userName parameter is optional. If set to "", the userName is determined
  278. // implicitly based on the AWS Access Key ID used to sign the request.
  279. //
  280. // See http://goo.gl/Vjozx for more details.
  281. func (iam *IAM) AccessKeys(userName string) (*AccessKeysResp, error) {
  282. params := map[string]string{
  283. "Action": "ListAccessKeys",
  284. }
  285. if userName != "" {
  286. params["UserName"] = userName
  287. }
  288. resp := new(AccessKeysResp)
  289. if err := iam.query(params, resp); err != nil {
  290. return nil, err
  291. }
  292. return resp, nil
  293. }
  294. // DeleteAccessKey deletes an access key from IAM.
  295. //
  296. // The userName parameter is optional. If set to "", the userName is determined
  297. // implicitly based on the AWS Access Key ID used to sign the request.
  298. //
  299. // See http://goo.gl/hPGhw for more details.
  300. func (iam *IAM) DeleteAccessKey(id, userName string) (*SimpleResp, error) {
  301. params := map[string]string{
  302. "Action": "DeleteAccessKey",
  303. "AccessKeyId": id,
  304. }
  305. if userName != "" {
  306. params["UserName"] = userName
  307. }
  308. resp := new(SimpleResp)
  309. if err := iam.query(params, resp); err != nil {
  310. return nil, err
  311. }
  312. return resp, nil
  313. }
  314. // Response to a GetUserPolicy request.
  315. //
  316. // See http://goo.gl/BH04O for more details.
  317. type GetUserPolicyResp struct {
  318. Policy UserPolicy `xml:"GetUserPolicyResult"`
  319. RequestId string `xml:"ResponseMetadata>RequestId"`
  320. }
  321. // UserPolicy encapsulates an IAM group policy.
  322. //
  323. // See http://goo.gl/C7hgS for more details.
  324. type UserPolicy struct {
  325. Name string `xml:"PolicyName"`
  326. UserName string `xml:"UserName"`
  327. Document string `xml:"PolicyDocument"`
  328. }
  329. // GetUserPolicy gets a user policy in IAM.
  330. //
  331. // See http://goo.gl/BH04O for more details.
  332. func (iam *IAM) GetUserPolicy(userName, policyName string) (*GetUserPolicyResp, error) {
  333. params := map[string]string{
  334. "Action": "GetUserPolicy",
  335. "UserName": userName,
  336. "PolicyName": policyName,
  337. }
  338. resp := new(GetUserPolicyResp)
  339. if err := iam.query(params, resp); err != nil {
  340. return nil, err
  341. }
  342. return resp, nil
  343. return nil, nil
  344. }
  345. // PutUserPolicy creates a user policy in IAM.
  346. //
  347. // See http://goo.gl/ldCO8 for more details.
  348. func (iam *IAM) PutUserPolicy(userName, policyName, policyDocument string) (*SimpleResp, error) {
  349. params := map[string]string{
  350. "Action": "PutUserPolicy",
  351. "UserName": userName,
  352. "PolicyName": policyName,
  353. "PolicyDocument": policyDocument,
  354. }
  355. resp := new(SimpleResp)
  356. if err := iam.postQuery(params, resp); err != nil {
  357. return nil, err
  358. }
  359. return resp, nil
  360. }
  361. // DeleteUserPolicy deletes a user policy from IAM.
  362. //
  363. // See http://goo.gl/7Jncn for more details.
  364. func (iam *IAM) DeleteUserPolicy(userName, policyName string) (*SimpleResp, error) {
  365. params := map[string]string{
  366. "Action": "DeleteUserPolicy",
  367. "PolicyName": policyName,
  368. "UserName": userName,
  369. }
  370. resp := new(SimpleResp)
  371. if err := iam.query(params, resp); err != nil {
  372. return nil, err
  373. }
  374. return resp, nil
  375. }
  376. // Response for AddUserToGroup requests.
  377. //
  378. // See http://goo.gl/ZnzRN for more details.
  379. type AddUserToGroupResp struct {
  380. RequestId string `xml:"ResponseMetadata>RequestId"`
  381. }
  382. // AddUserToGroup adds a user to a specific group
  383. //
  384. // See http://goo.gl/ZnzRN for more details.
  385. func (iam *IAM) AddUserToGroup(name, group string) (*AddUserToGroupResp, error) {
  386. params := map[string]string{
  387. "Action": "AddUserToGroup",
  388. "GroupName": group,
  389. "UserName": name}
  390. resp := new(AddUserToGroupResp)
  391. if err := iam.query(params, resp); err != nil {
  392. return nil, err
  393. }
  394. return resp, nil
  395. }
  396. // Response for a ListAccountAliases request.
  397. //
  398. // See http://goo.gl/MMN79v for more details.
  399. type ListAccountAliasesResp struct {
  400. AccountAliases []string `xml:"ListAccountAliasesResult>AccountAliases>member"`
  401. RequestId string `xml:"ResponseMetadata>RequestId"`
  402. }
  403. // ListAccountAliases lists the account aliases associated with the account
  404. //
  405. // See http://goo.gl/MMN79v for more details.
  406. func (iam *IAM) ListAccountAliases() (*ListAccountAliasesResp, error) {
  407. params := map[string]string{
  408. "Action": "ListAccountAliases",
  409. }
  410. resp := new(ListAccountAliasesResp)
  411. if err := iam.query(params, resp); err != nil {
  412. return nil, err
  413. }
  414. return resp, nil
  415. }
  416. // Response for a CreateAccountAlias request.
  417. //
  418. // See http://goo.gl/oU5C4H for more details.
  419. type CreateAccountAliasResp struct {
  420. RequestId string `xml:"ResponseMetadata>RequestId"`
  421. }
  422. // CreateAccountAlias creates an alias for your AWS account.
  423. //
  424. // See http://goo.gl/oU5C4H for more details.
  425. func (iam *IAM) CreateAccountAlias(alias string) (*CreateAccountAliasResp, error) {
  426. params := map[string]string{
  427. "Action": "CreateAccountAlias",
  428. "AccountAlias": alias,
  429. }
  430. resp := new(CreateAccountAliasResp)
  431. if err := iam.query(params, resp); err != nil {
  432. return nil, err
  433. }
  434. return resp, nil
  435. }
  436. // Response for a DeleteAccountAlias request.
  437. //
  438. // See http://goo.gl/hKalgg for more details.
  439. type DeleteAccountAliasResp struct {
  440. RequestId string `xml:"ResponseMetadata>RequestId"`
  441. }
  442. // DeleteAccountAlias deletes the specified AWS account alias.
  443. //
  444. // See http://goo.gl/hKalgg for more details.
  445. func (iam *IAM) DeleteAccountAlias(alias string) (*DeleteAccountAliasResp, error) {
  446. params := map[string]string{
  447. "Action": "DeleteAccountAlias",
  448. "AccountAlias": alias,
  449. }
  450. resp := new(DeleteAccountAliasResp)
  451. if err := iam.query(params, resp); err != nil {
  452. return nil, err
  453. }
  454. return resp, nil
  455. }
  456. type SimpleResp struct {
  457. RequestId string `xml:"ResponseMetadata>RequestId"`
  458. }
  459. type xmlErrors struct {
  460. Errors []Error `xml:"Error"`
  461. }
  462. // ServerCertificateMetadata represents a ServerCertificateMetadata object
  463. //
  464. // See http://goo.gl/Rfu7LD for more details.
  465. type ServerCertificateMetadata struct {
  466. Arn string `xml:"Arn"`
  467. Expiration time.Time `xml:"Expiration"`
  468. Path string `xml:"Path"`
  469. ServerCertificateId string `xml:"ServerCertificateId"`
  470. ServerCertificateName string `xml:"ServerCertificateName"`
  471. UploadDate time.Time `xml:"UploadDate"`
  472. }
  473. // UploadServerCertificateResponse wraps up for UploadServerCertificate request.
  474. //
  475. // See http://goo.gl/bomzce for more details.
  476. type UploadServerCertificateResponse struct {
  477. ServerCertificateMetadata ServerCertificateMetadata `xml:"UploadServerCertificateResult>ServerCertificateMetadata"`
  478. RequestId string `xml:"ResponseMetadata>RequestId"`
  479. }
  480. // UploadServerCertificateParams wraps up the params to be passed for the UploadServerCertificate request
  481. //
  482. // See http://goo.gl/bomzce for more details.
  483. type UploadServerCertificateParams struct {
  484. ServerCertificateName string
  485. PrivateKey string
  486. CertificateBody string
  487. CertificateChain string
  488. Path string
  489. }
  490. // UploadServerCertificate uploads a server certificate entity for the AWS account.
  491. //
  492. // Required Params: ServerCertificateName, PrivateKey, CertificateBody
  493. //
  494. // See http://goo.gl/bomzce for more details.
  495. func (iam *IAM) UploadServerCertificate(options *UploadServerCertificateParams) (
  496. *UploadServerCertificateResponse, error) {
  497. params := map[string]string{
  498. "Action": "UploadServerCertificate",
  499. "ServerCertificateName": options.ServerCertificateName,
  500. "PrivateKey": options.PrivateKey,
  501. "CertificateBody": options.CertificateBody,
  502. }
  503. if options.CertificateChain != "" {
  504. params["CertificateChain"] = options.CertificateChain
  505. }
  506. if options.Path != "" {
  507. params["Path"] = options.Path
  508. }
  509. resp := new(UploadServerCertificateResponse)
  510. if err := iam.postQuery(params, resp); err != nil {
  511. return nil, err
  512. }
  513. return resp, nil
  514. }
  515. // ListServerCertificates lists all available certificates for the AWS account specified
  516. //
  517. // Required Params: None
  518. //
  519. // Optional Params: Marker, and, PathPrefix
  520. //
  521. // See http://goo.gl/bwn0Nb for specifics
  522. type ListServerCertificatesParams struct {
  523. Marker string
  524. PathPrefix string
  525. }
  526. type ListServerCertificatesResp struct {
  527. ServerCertificates []ServerCertificateMetadata `xml:"ListServerCertificatesResult>ServerCertificateMetadataList>member>ServerCertificateMetadata"`
  528. RequestId string `xml:"ResponseMetadata>RequestId"`
  529. IsTruncated bool `xml:"ListServerCertificatesResult>IsTruncated"`
  530. }
  531. func (iam *IAM) ListServerCertificates(options *ListServerCertificatesParams) (
  532. *ListServerCertificatesResp, error) {
  533. params := map[string]string{
  534. "Action": "ListServerCertificates",
  535. }
  536. if options.Marker != "" {
  537. params["Marker"] = options.Marker
  538. }
  539. if options.PathPrefix != "" {
  540. params["PathPrefix"] = options.PathPrefix
  541. }
  542. resp := new(ListServerCertificatesResp)
  543. if err := iam.query(params, resp); err != nil {
  544. return nil, err
  545. }
  546. return resp, nil
  547. }
  548. // DeleteServerCertificate deletes the specified server certificate.
  549. //
  550. // See http://goo.gl/W4nmxQ for more details.
  551. func (iam *IAM) DeleteServerCertificate(serverCertificateName string) (*SimpleResp, error) {
  552. params := map[string]string{
  553. "Action": "DeleteServerCertificate",
  554. "ServerCertificateName": serverCertificateName,
  555. }
  556. resp := new(SimpleResp)
  557. if err := iam.postQuery(params, resp); err != nil {
  558. return nil, err
  559. }
  560. return resp, nil
  561. }
  562. // Error encapsulates an IAM error.
  563. type Error struct {
  564. // HTTP status code of the error.
  565. StatusCode int
  566. // AWS code of the error.
  567. Code string
  568. // Message explaining the error.
  569. Message string
  570. }
  571. func (e *Error) Error() string {
  572. var prefix string
  573. if e.Code != "" {
  574. prefix = e.Code + ": "
  575. }
  576. if prefix == "" && e.StatusCode > 0 {
  577. prefix = strconv.Itoa(e.StatusCode) + ": "
  578. }
  579. return prefix + e.Message
  580. }