yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/aws/iam_policy.go (about)

     1  // Copyright 2019 Yunion
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package aws
    16  
    17  import (
    18  	"fmt"
    19  	"net/url"
    20  	"strings"
    21  	"time"
    22  
    23  	"yunion.io/x/jsonutils"
    24  	"yunion.io/x/pkg/errors"
    25  
    26  	api "yunion.io/x/cloudmux/pkg/apis/compute"
    27  	"yunion.io/x/cloudmux/pkg/cloudprovider"
    28  )
    29  
    30  type SPolicies struct {
    31  	IsTruncated bool      `xml:"IsTruncated"`
    32  	Marker      string    `xml:"Marker"`
    33  	Policies    []SPolicy `xml:"Policies>member"`
    34  }
    35  
    36  type SPolicy struct {
    37  	client *SAwsClient
    38  
    39  	PermissionsBoundaryUsageCount int       `xml:"PermissionsBoundaryUsageCount"`
    40  	PolicyName                    string    `xml:"PolicyName"`
    41  	Description                   string    `xml:"Description"`
    42  	DefaultVersionId              string    `xml:"DefaultVersionId"`
    43  	PolicyId                      string    `xml:"PolicyId"`
    44  	Path                          string    `xml:"Path"`
    45  	Arn                           string    `xml:"Arn"`
    46  	IsAttachable                  bool      `xml:"IsAttachable"`
    47  	AttachmentCount               int       `xml:"AttachmentCount"`
    48  	CreateDate                    time.Time `xml:"CreateDate"`
    49  	UpdateDate                    time.Time `xml:"UpdateDate"`
    50  }
    51  
    52  func (self *SPolicy) GetName() string {
    53  	return self.PolicyName
    54  }
    55  
    56  func (self *SPolicy) GetGlobalId() string {
    57  	return self.client.getIamCommonArn(self.Arn)
    58  }
    59  
    60  func (self *SPolicy) GetDescription() string {
    61  	policy, err := self.client.GetPolicy(self.Arn)
    62  	if err != nil {
    63  		return ""
    64  	}
    65  	return policy.Description
    66  }
    67  
    68  type SUserPolicies struct {
    69  	PolicyNames []string `xml:"PolicyNames>member"`
    70  	IsTruncated bool     `xml:"IsTruncated"`
    71  }
    72  
    73  func (self *SAwsClient) GetCustomPolicyMaps() (map[string]string, error) {
    74  	policyMaps := map[string]string{}
    75  	offset := ""
    76  	for {
    77  		part, err := self.ListPolicies(offset, 1000, false, "", "", "Local")
    78  		if err != nil {
    79  			return nil, errors.Wrapf(err, "ListPolicies")
    80  		}
    81  		for _, policy := range part.Policies {
    82  			policyMaps[policy.PolicyName] = policy.PolicyId
    83  		}
    84  		offset = part.Marker
    85  		if len(offset) == 0 || !part.IsTruncated {
    86  			break
    87  		}
    88  	}
    89  	return policyMaps, nil
    90  }
    91  
    92  func (self *SAwsClient) ListUserPolicies(userName string, marker string, maxItems int) (*SUserPolicies, error) {
    93  	if maxItems <= 0 || maxItems > 1000 {
    94  		maxItems = 1000
    95  	}
    96  	params := map[string]string{
    97  		"UserName": userName,
    98  		"MaxItems": fmt.Sprintf("%d", maxItems),
    99  	}
   100  	if len(marker) > 0 {
   101  		params["Marker"] = marker
   102  	}
   103  	policies := SUserPolicies{}
   104  	err := self.iamRequest("ListUserPolicies", params, &policies)
   105  	if err != nil {
   106  		return nil, errors.Wrap(err, "iamRequest.ListUserPolicies")
   107  	}
   108  	return &policies, nil
   109  }
   110  
   111  func (self *SPolicy) Delete() error {
   112  	return self.client.DeletePolicy(self.Arn)
   113  }
   114  
   115  func (self *SPolicy) UpdateDocument(document *jsonutils.JSONDict) error {
   116  	return cloudprovider.ErrNotImplemented
   117  }
   118  
   119  func (self *SPolicy) GetDocument() (*jsonutils.JSONDict, error) {
   120  	return self.client.GetDocument(self.Arn, self.DefaultVersionId)
   121  }
   122  
   123  func (self *SAwsClient) GetDocument(arn, versionId string) (*jsonutils.JSONDict, error) {
   124  	version, err := self.GetPolicyVersion(arn, versionId)
   125  	if err != nil {
   126  		return nil, errors.Wrapf(err, "GetPolicyVersion(%s, %s)", arn, versionId)
   127  	}
   128  	document, err := url.PathUnescape(version.Document)
   129  	if err != nil {
   130  		return nil, errors.Wrapf(err, "url.PathUnescape.document")
   131  	}
   132  	jsonObj, err := jsonutils.Parse([]byte(document))
   133  	if err != nil {
   134  		return nil, errors.Wrap(err, "jsonutils.Parse")
   135  	}
   136  	return jsonObj.(*jsonutils.JSONDict), nil
   137  }
   138  
   139  func (self *SAwsClient) GetISystemCloudpolicies() ([]cloudprovider.ICloudpolicy, error) {
   140  	ret := []cloudprovider.ICloudpolicy{}
   141  	marker := ""
   142  	for {
   143  		part, err := self.ListPolicies(marker, 1000, false, "", "PermissionsPolicy", "AWS")
   144  		if err != nil {
   145  			return nil, errors.Wrapf(err, "ListPolicies")
   146  		}
   147  		for i := range part.Policies {
   148  			part.Policies[i].client = self
   149  			ret = append(ret, &part.Policies[i])
   150  		}
   151  		marker = part.Marker
   152  		if len(marker) == 0 || !part.IsTruncated {
   153  			break
   154  		}
   155  	}
   156  	return ret, nil
   157  }
   158  
   159  func (self *SAwsClient) GetICustomCloudpolicies() ([]cloudprovider.ICloudpolicy, error) {
   160  	ret := []cloudprovider.ICloudpolicy{}
   161  	marker := ""
   162  	for {
   163  		part, err := self.ListPolicies(marker, 1000, false, "", "PermissionsPolicy", "Local")
   164  		if err != nil {
   165  			return nil, errors.Wrapf(err, "ListPolicies")
   166  		}
   167  		for i := range part.Policies {
   168  			part.Policies[i].client = self
   169  			ret = append(ret, &part.Policies[i])
   170  		}
   171  		marker = part.Marker
   172  		if len(marker) == 0 || !part.IsTruncated {
   173  			break
   174  		}
   175  	}
   176  	return ret, nil
   177  }
   178  
   179  func (self *SAwsClient) ListPolicies(marker string, maxItems int, onlyAttached bool, pathPrefix string, policyUsageFilter string, scope string) (*SPolicies, error) {
   180  	if maxItems <= 0 || maxItems > 1000 {
   181  		maxItems = 1000
   182  	}
   183  
   184  	params := map[string]string{
   185  		"MaxItems": fmt.Sprintf("%d", maxItems),
   186  	}
   187  	if len(marker) > 0 {
   188  		params["Marker"] = marker
   189  	}
   190  	if onlyAttached {
   191  		params["OnlyAttached"] = "true"
   192  	}
   193  	if len(pathPrefix) > 0 {
   194  		params["PathPrefix"] = pathPrefix
   195  	}
   196  	if len(policyUsageFilter) > 0 {
   197  		params["PolicyUsageFilter"] = policyUsageFilter
   198  	}
   199  	if len(scope) > 0 {
   200  		params["Scope"] = scope
   201  	}
   202  	policies := &SPolicies{}
   203  	err := self.iamRequest("ListPolicies", params, policies)
   204  	if err != nil {
   205  		return nil, errors.Wrap(err, "iamRequest.ListPolicies")
   206  	}
   207  	return policies, nil
   208  }
   209  
   210  func (self *SAwsClient) ListAttachedUserPolicies(userName string, marker string, maxItems int, pathPrefix string) (*SAttachedPolicies, error) {
   211  	if maxItems <= 0 || maxItems > 1000 {
   212  		maxItems = 1000
   213  	}
   214  	params := map[string]string{
   215  		"MaxItems": fmt.Sprintf("%d", maxItems),
   216  	}
   217  	if len(marker) > 0 {
   218  		params["Marker"] = marker
   219  	}
   220  	if len(pathPrefix) > 0 {
   221  		params["PathPrefix"] = pathPrefix
   222  	}
   223  	if len(userName) > 0 {
   224  		params["UserName"] = userName
   225  	}
   226  	policies := &SAttachedPolicies{}
   227  	err := self.iamRequest("ListAttachedUserPolicies", params, policies)
   228  	if err != nil {
   229  		return nil, errors.Wrap(err, "ListAttachedUserPolicies")
   230  	}
   231  	return policies, nil
   232  }
   233  
   234  type SAttachedPolicies struct {
   235  	IsTruncated      bool              `xml:"IsTruncated"`
   236  	Marker           string            `xml:"Marker"`
   237  	AttachedPolicies []SAttachedPolicy `xml:"AttachedPolicies>member"`
   238  }
   239  
   240  type SAttachedPolicy struct {
   241  	client *SAwsClient
   242  
   243  	PolicyName string `xml:"PolicyName"`
   244  	PolicyArn  string `xml:"PolicyArn"`
   245  }
   246  
   247  func (self *SAttachedPolicy) GetGlobalId() string {
   248  	return self.client.getIamCommonArn(self.PolicyArn)
   249  }
   250  
   251  func (self *SAttachedPolicy) GetName() string {
   252  	return self.PolicyName
   253  }
   254  
   255  func (self *SAttachedPolicy) GetDescription() string {
   256  	return ""
   257  }
   258  
   259  func (self *SAttachedPolicy) UpdateDocument(document *jsonutils.JSONDict) error {
   260  	return self.client.CreatePolicyVersion(self.PolicyArn, document.String(), true)
   261  }
   262  
   263  func (self *SAttachedPolicy) GetDocument() (*jsonutils.JSONDict, error) {
   264  	return nil, cloudprovider.ErrNotImplemented
   265  }
   266  
   267  func (self *SAttachedPolicy) Delete() error {
   268  	return cloudprovider.ErrNotImplemented
   269  }
   270  
   271  func (self *SAwsClient) ListAttachedGroupPolicies(name string, marker string, maxItems int) (*SAttachedPolicies, error) {
   272  	if maxItems <= 0 || maxItems > 1000 {
   273  		maxItems = 1000
   274  	}
   275  
   276  	params := map[string]string{
   277  		"GroupName": name,
   278  		"MaxItems":  fmt.Sprintf("%d", maxItems),
   279  	}
   280  	if len(marker) > 0 {
   281  		params["Marker"] = marker
   282  	}
   283  	policies := &SAttachedPolicies{}
   284  	err := self.iamRequest("ListAttachedGroupPolicies", params, policies)
   285  	if err != nil {
   286  		return nil, errors.Wrap(err, "iamRequest.ListGroupPolicies")
   287  	}
   288  	return policies, nil
   289  }
   290  
   291  type SPolicyNames struct {
   292  	PolicyNames []string `xml:"PolicyNames>member"`
   293  	IsTruncated bool     `xml:"IsTruncated"`
   294  }
   295  
   296  func (self *SAwsClient) ListRolePolicies(roleName string, marker string, maxItems int) (*SPolicyNames, error) {
   297  	if maxItems < 1 || maxItems > 1000 {
   298  		maxItems = 1000
   299  	}
   300  	params := map[string]string{
   301  		"RoleName": roleName,
   302  		"MaxItems": fmt.Sprintf("%d", maxItems),
   303  	}
   304  	if len(marker) > 0 {
   305  		params["Marker"] = marker
   306  	}
   307  	names := &SPolicyNames{}
   308  	err := self.iamRequest("ListRolePolicies", params, names)
   309  	if err != nil {
   310  		return nil, errors.Wrapf(err, "ListRolePolicies")
   311  	}
   312  	return names, nil
   313  }
   314  
   315  func (self *SAwsClient) ListAttachedRolePolicies(roleName string, marker string, maxItems int, pathPrefix string) (*SAttachedPolicies, error) {
   316  	if maxItems < 1 || maxItems > 1000 {
   317  		maxItems = 1000
   318  	}
   319  	params := map[string]string{
   320  		"RoleName": roleName,
   321  		"MaxItems": fmt.Sprintf("%d", maxItems),
   322  	}
   323  	if len(marker) > 0 {
   324  		params["marker"] = marker
   325  	}
   326  	policies := &SAttachedPolicies{}
   327  	err := self.iamRequest("ListAttachedRolePolicies", params, policies)
   328  	if err != nil {
   329  		return nil, errors.Wrapf(err, "ListAttachedRolePolicies")
   330  	}
   331  	return policies, nil
   332  }
   333  
   334  func (self *SAwsClient) AttachRolePolicy(roleName, policyArn string) error {
   335  	params := map[string]string{
   336  		"PolicyArn": policyArn,
   337  		"RoleName":  roleName,
   338  	}
   339  	return self.iamRequest("AttachRolePolicy", params, nil)
   340  }
   341  
   342  func (self *SAwsClient) DetachRolePolicy(roleName string, policyArn string) error {
   343  	params := map[string]string{
   344  		"PolicyArn": policyArn,
   345  		"RoleName":  roleName,
   346  	}
   347  	err := self.iamRequest("DetachRolePolicy", params, nil)
   348  	if err != nil && errors.Cause(err) != cloudprovider.ErrNotFound {
   349  		return errors.Wrap(err, "DetachRolePolicy")
   350  	}
   351  	return nil
   352  }
   353  
   354  type SPolicyVersion struct {
   355  	Document         string    `xml:"Document"`
   356  	IsDefaultVersion bool      `xml:"IsDefaultVersion"`
   357  	VersionId        string    `xml:"VersionId"`
   358  	CreateDate       time.Time `xml:"CreateDate"`
   359  }
   360  
   361  type SPolicyVersions struct {
   362  	Versions    []SPolicyVersion `xml:"Versions>member"`
   363  	IsTruncated bool             `xml:"IsTruncated"`
   364  	Marker      string           `xml:"Marker"`
   365  }
   366  
   367  func (self *SAwsClient) ListPolicyVersions(marker string, maxItems int, arn string) (*SPolicyVersions, error) {
   368  	if maxItems < 1 || maxItems > 1000 {
   369  		maxItems = 1000
   370  	}
   371  	params := map[string]string{
   372  		"MaxItems":  fmt.Sprintf("%d", maxItems),
   373  		"PolicyArn": arn,
   374  	}
   375  	if len(marker) > 0 {
   376  		params["Marker"] = marker
   377  	}
   378  	versions := &SPolicyVersions{}
   379  	err := self.iamRequest("ListPolicyVersions", params, versions)
   380  	if err != nil {
   381  		return nil, errors.Wrapf(err, "ListPolicyVersions")
   382  	}
   383  	return versions, nil
   384  }
   385  
   386  func (self *SAwsClient) GetPolicyVersion(arn, versionId string) (*SPolicyVersion, error) {
   387  	params := map[string]string{
   388  		"PolicyArn": arn,
   389  		"VersionId": versionId,
   390  	}
   391  	result := struct {
   392  		Version SPolicyVersion `xml:"PolicyVersion"`
   393  	}{}
   394  	err := self.iamRequest("GetPolicyVersion", params, &result)
   395  	if err != nil {
   396  		return nil, errors.Wrapf(err, "GetPolicyVersion")
   397  	}
   398  	return &result.Version, nil
   399  }
   400  
   401  func (self *SAwsClient) GetPolicy(arn string) (*SPolicy, error) {
   402  	params := map[string]string{
   403  		"PolicyArn": arn,
   404  	}
   405  	result := struct {
   406  		Policy SPolicy `xml:"Policy"`
   407  	}{}
   408  	err := self.iamRequest("GetPolicy", params, &result)
   409  	if err != nil {
   410  		return nil, errors.Wrapf(err, "GetPolicy")
   411  	}
   412  	return &result.Policy, nil
   413  }
   414  
   415  func (self *SAwsClient) CreateICloudpolicy(opts *cloudprovider.SCloudpolicyCreateOptions) (cloudprovider.ICloudpolicy, error) {
   416  	policy, err := self.CreatePolicy(opts.Name, opts.Document.String(), "", opts.Desc)
   417  	if err != nil {
   418  		return nil, errors.Wrapf(err, "CreatePolicy")
   419  	}
   420  	return policy, nil
   421  }
   422  
   423  func (self *SAwsClient) CreatePolicy(name, document, path, desc string) (*SPolicy, error) {
   424  	document = self.convertDocument(document)
   425  	params := map[string]string{
   426  		"PolicyName":     name,
   427  		"PolicyDocument": document,
   428  	}
   429  	if len(path) > 0 {
   430  		params["Path"] = path
   431  	}
   432  	if len(desc) > 0 {
   433  		params["Description"] = desc
   434  	}
   435  	ret := struct {
   436  		Policy SPolicy `xml:"Policy"`
   437  	}{}
   438  	err := self.iamRequest("CreatePolicy", params, &ret)
   439  	if err != nil {
   440  		return nil, errors.Wrapf(err, "CreatePolicy")
   441  	}
   442  	ret.Policy.client = self
   443  	return &ret.Policy, nil
   444  }
   445  
   446  func (self *SAwsClient) DeletePolicy(arn string) error {
   447  	params := map[string]string{
   448  		"PolicyArn": arn,
   449  	}
   450  	err := self.iamRequest("DeletePolicy", params, nil)
   451  	if err != nil && errors.Cause(err) != cloudprovider.ErrNotFound {
   452  		return err
   453  	}
   454  	return nil
   455  }
   456  
   457  func (self *SAwsClient) convertDocument(document string) string {
   458  	switch self.GetAccessEnv() {
   459  	case api.CLOUD_ACCESS_ENV_AWS_GLOBAL:
   460  		return strings.ReplaceAll(document, "arn:aws-cn", "arn:aws")
   461  	default:
   462  		return strings.ReplaceAll(document, "arn:aws", "arn:aws-cn")
   463  	}
   464  }
   465  
   466  func (self *SAwsClient) CreatePolicyVersion(arn, document string, isDefault bool) error {
   467  	document = self.convertDocument(document)
   468  	params := map[string]string{
   469  		"PolicyArn":      arn,
   470  		"PolicyDocument": document,
   471  	}
   472  	if isDefault {
   473  		params["SetAsDefault"] = "true"
   474  	}
   475  	return self.iamRequest("CreatePolicyVersion", params, nil)
   476  }