yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/qcloud/cam_role.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 qcloud
    16  
    17  import (
    18  	"fmt"
    19  	"strconv"
    20  	"strings"
    21  	"time"
    22  
    23  	"yunion.io/x/jsonutils"
    24  	"yunion.io/x/pkg/errors"
    25  
    26  	"yunion.io/x/cloudmux/pkg/cloudprovider"
    27  	"yunion.io/x/cloudmux/pkg/multicloud"
    28  )
    29  
    30  const (
    31  	DEFAULT_ROLE_DOCUMENT = `{"version":"2.0","statement":[{"action":"name/sts:AssumeRole","effect":"allow","principal":{"service":["cvm.qcloud.com"]}}]}`
    32  )
    33  
    34  /*
    35  "AddTime": "2020-08-11 17:03:30",
    36  "ConsoleLogin": 0.000000,
    37  "Description": "hello",
    38  "PolicyDocument": "{\"version\":\"2.0\",\"statement\":[{\"action\":\"name/sts:AssumeRole\",\"effect\":\"allow\",\"principal\":{\"service\":[\"cdb.qcloud.com\",\"blueking.cloud.tencent.com\"]}}]}",
    39  "RoleId": "4611686018428392276",
    40  "RoleName": "test-role",
    41  "RoleType": "user",
    42  "SessionDuration": 0.000000,
    43  "UpdateTime": "2020-08-11 17:03:30"
    44  */
    45  
    46  type SPrincipal struct {
    47  	Federated []string
    48  }
    49  
    50  type Statement struct {
    51  	Action    string
    52  	Effect    string
    53  	Principal SPrincipal
    54  }
    55  
    56  type SRole struct {
    57  	multicloud.SResourceBase
    58  	client *SQcloudClient
    59  
    60  	AddTime         time.Time
    61  	ConsoleLogin    float32
    62  	Description     string
    63  	PolicyDocument  string
    64  	RoleId          string
    65  	RoleName        string
    66  	RoleType        string
    67  	SessionDuration float32
    68  	UpdateTime      time.Time
    69  }
    70  
    71  func (self *SRole) GetGlobalId() string {
    72  	return self.RoleName
    73  }
    74  
    75  func (self *SRole) GetName() string {
    76  	return self.RoleName
    77  }
    78  
    79  func (self *SRole) GetDocument() *jsonutils.JSONDict {
    80  	if len(self.PolicyDocument) > 0 {
    81  		document, err := jsonutils.Parse([]byte(self.PolicyDocument))
    82  		if err != nil {
    83  			return nil
    84  		}
    85  		return document.(*jsonutils.JSONDict)
    86  	}
    87  	return nil
    88  }
    89  
    90  func (self *SRole) GetSAMLProvider() string {
    91  	document := self.GetDocument()
    92  	if document != nil {
    93  		statements := []Statement{}
    94  		document.Unmarshal(&statements, "statement")
    95  		for i := range statements {
    96  			if statements[i].Action == "name/sts:AssumeRoleWithSAML" {
    97  				for _, federated := range statements[i].Principal.Federated {
    98  					if strings.Contains(federated, ":saml-provider/") {
    99  						info := strings.Split(federated, "/")
   100  						return info[len(info)-1]
   101  					}
   102  				}
   103  			}
   104  		}
   105  	}
   106  	return ""
   107  }
   108  
   109  func (self *SRole) Delete() error {
   110  	return self.client.DeleteRole(self.RoleName)
   111  }
   112  
   113  func (self *SRole) GetICloudpolicies() ([]cloudprovider.ICloudpolicy, error) {
   114  	ret := []cloudprovider.ICloudpolicy{}
   115  	for {
   116  		part, total, err := self.client.ListAttachedRolePolicies(self.RoleName, "", len(ret), 50)
   117  		if err != nil {
   118  			return nil, errors.Wrapf(err, "ListAttachedRolePolicies")
   119  		}
   120  		for i := range part {
   121  			part[i].client = self.client
   122  			ret = append(ret, &part[i])
   123  		}
   124  		if len(ret) >= total {
   125  			break
   126  		}
   127  	}
   128  	return ret, nil
   129  }
   130  
   131  func (self *SRole) AttachPolicy(id string) error {
   132  	return self.client.AttachRolePolicy(self.RoleName, id)
   133  }
   134  
   135  func (self *SRole) DetachPolicy(id string) error {
   136  	return self.client.DetachRolePolicy(self.RoleName, id)
   137  }
   138  
   139  func (self *SQcloudClient) GetICloudroles() ([]cloudprovider.ICloudrole, error) {
   140  	ret := []cloudprovider.ICloudrole{}
   141  	for {
   142  		part, total, err := self.DescribeRoleList(len(ret), 200)
   143  		if err != nil {
   144  			return nil, errors.Wrapf(err, "DescribeRoleList")
   145  		}
   146  		for i := range part {
   147  			part[i].client = self
   148  			ret = append(ret, &part[i])
   149  		}
   150  		if len(ret) >= total {
   151  			break
   152  		}
   153  	}
   154  	return ret, nil
   155  }
   156  
   157  func (self *SQcloudClient) DescribeRoleList(offset int, limit int) ([]SRole, int, error) {
   158  	if limit < 1 || limit > 200 {
   159  		limit = 200
   160  	}
   161  	if offset < 1 {
   162  		offset = 1
   163  	}
   164  	params := map[string]string{
   165  		"Page": fmt.Sprintf("%d", offset),
   166  		"Rp":   fmt.Sprintf("%d", limit),
   167  	}
   168  	roles := []SRole{}
   169  	resp, err := self.camRequest("DescribeRoleList", params)
   170  	if err != nil {
   171  		return nil, 0, errors.Wrapf(err, "DescribeRoleList")
   172  	}
   173  	err = resp.Unmarshal(&roles, "List")
   174  	if err != nil {
   175  		return nil, 0, errors.Wrapf(err, "resp.Unmarshal")
   176  	}
   177  	total, _ := resp.Float("TotalNum")
   178  	return roles, int(total), nil
   179  }
   180  
   181  func (self *SQcloudClient) CreateRole(name, document, desc string) (*SRole, error) {
   182  	if len(document) == 0 {
   183  		document = DEFAULT_ROLE_DOCUMENT
   184  	}
   185  	params := map[string]string{
   186  		"RoleName":        name,
   187  		"PolicyDocument":  document,
   188  		"ConsoleLogin":    "1",
   189  		"SessionDuration": "43200",
   190  		"Description":     desc,
   191  	}
   192  	_, err := self.camRequest("CreateRole", params)
   193  	if err != nil {
   194  		return nil, errors.Wrap(err, "CreateRole")
   195  	}
   196  	return self.GetRole(name)
   197  }
   198  
   199  func (self *SQcloudClient) GetRole(name string) (*SRole, error) {
   200  	params := map[string]string{
   201  		"RoleName": name,
   202  	}
   203  	resp, err := self.camRequest("GetRole", params)
   204  	if err != nil {
   205  		return nil, errors.Wrapf(err, "GetRole(%s)", name)
   206  	}
   207  	role := &SRole{client: self}
   208  	err = resp.Unmarshal(role, "RoleInfo")
   209  	if err != nil {
   210  		return nil, errors.Wrapf(err, "resp.Unmarshal")
   211  	}
   212  	return role, nil
   213  }
   214  
   215  func (self *SQcloudClient) ListAttachedRolePolicies(roleName, policyType string, offset, limit int) ([]SPolicy, int, error) {
   216  	if limit < 1 || limit > 200 {
   217  		limit = 200
   218  	}
   219  	if offset < 1 {
   220  		offset = 1
   221  	}
   222  	params := map[string]string{
   223  		"Page":     fmt.Sprintf("%d", offset),
   224  		"Rp":       fmt.Sprintf("%d", limit),
   225  		"RoleName": roleName,
   226  	}
   227  	if len(policyType) > 0 {
   228  		params["PolicyType"] = policyType
   229  	}
   230  	resp, err := self.camRequest("ListAttachedRolePolicies", params)
   231  	if err != nil {
   232  		return nil, 0, errors.Wrapf(err, "ListAttachedRolePolicies")
   233  	}
   234  	policies := []SPolicy{}
   235  	err = resp.Unmarshal(&policies, "List")
   236  	if err != nil {
   237  		return nil, 0, errors.Wrapf(err, "resp.Unmarshal")
   238  	}
   239  	total, _ := resp.Float("TotalNum")
   240  	return policies, int(total), nil
   241  }
   242  
   243  func (self *SQcloudClient) DeleteRole(name string) error {
   244  	params := map[string]string{
   245  		"RoleName": name,
   246  	}
   247  	_, err := self.camRequest("DeleteRole", params)
   248  	return err
   249  }
   250  
   251  func (self *SQcloudClient) AttachRolePolicy(roleName string, policyId string) error {
   252  	params := map[string]string{
   253  		"AttachRoleName": roleName,
   254  	}
   255  	if _id, _ := strconv.Atoi(policyId); _id > 0 {
   256  		params["PolicyId"] = policyId
   257  	} else {
   258  		params["PolicyName"] = policyId
   259  	}
   260  	_, err := self.camRequest("AttachRolePolicy", params)
   261  	return err
   262  }
   263  
   264  func (self *SQcloudClient) DetachRolePolicy(roleName string, policyId string) error {
   265  	params := map[string]string{
   266  		"DetachRoleName": roleName,
   267  	}
   268  	if _id, _ := strconv.Atoi(policyId); _id > 0 {
   269  		params["PolicyId"] = policyId
   270  	} else {
   271  		params["PolicyName"] = policyId
   272  	}
   273  	_, err := self.camRequest("DetachRolePolicy", params)
   274  	return err
   275  }