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 }