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 }