yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/aws/iam_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 aws 16 17 import ( 18 "fmt" 19 "net/url" 20 "time" 21 22 "yunion.io/x/jsonutils" 23 "yunion.io/x/pkg/errors" 24 25 api "yunion.io/x/cloudmux/pkg/apis/compute" 26 "yunion.io/x/cloudmux/pkg/cloudprovider" 27 ) 28 29 var ( 30 samlRole = `{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":"sts:AssumeRoleWithSAML","Principal":{"Federated":"%s"},"Condition":{"StringEquals":{"SAML:aud":["%s"]}}}]}` 31 ) 32 33 type SRole struct { 34 client *SAwsClient 35 36 Path string `xml:"Path"` 37 AssumeRolePolicyDocument string `xml:"AssumeRolePolicyDocument"` 38 MaxSessionDuration int `xml:"MaxSessionDuration"` 39 RoleId string `xml:"RoleId"` 40 RoleName string `xml:"RoleName"` 41 Description string `xml:"Description"` 42 Arn string `xml:"Arn"` 43 CreateDate time.Time `xml:"CreateDate"` 44 } 45 46 func (self *SRole) GetGlobalId() string { 47 return self.Arn 48 } 49 50 func (self *SRole) GetName() string { 51 return self.RoleName 52 } 53 54 func (self *SRole) Delete() error { 55 return self.client.DeleteRole(self.RoleName) 56 } 57 58 func (self *SRole) GetDocument() *jsonutils.JSONDict { 59 data, err := url.QueryUnescape(self.AssumeRolePolicyDocument) 60 if err != nil { 61 return nil 62 } 63 document, err := jsonutils.Parse([]byte(data)) 64 if err != nil { 65 return nil 66 } 67 return document.(*jsonutils.JSONDict) 68 } 69 70 //[{"Action":"sts:AssumeRoleWithSAML","Condition":{"StringEquals":{"SAML:aud":"https://signin.aws.amazon.com/saml"}},"Effect":"Allow","Principal":{"Federated":"arn:aws:iam::879324515906:saml-provider/quxuan"}}] 71 func (self *SRole) GetSAMLProvider() string { 72 document := self.GetDocument() 73 if document != nil { 74 statement, err := document.GetArray("Statement") 75 if err == nil { 76 for i := range statement { 77 if action, _ := statement[i].GetString("Action"); action == "sts:AssumeRoleWithSAML" { 78 sp, _ := statement[i].GetString("Principal", "Federated") 79 if len(sp) > 0 { 80 return sp 81 } 82 } 83 } 84 } 85 } 86 return "" 87 } 88 89 func (self *SRole) AttachPolicy(id string) error { 90 return self.client.AttachRolePolicy(self.RoleName, self.client.getIamArn(id)) 91 } 92 93 func (self *SRole) DetachPolicy(id string) error { 94 return self.client.DetachRolePolicy(self.RoleName, self.client.getIamArn(id)) 95 } 96 97 func (self *SRole) GetICloudpolicies() ([]cloudprovider.ICloudpolicy, error) { 98 policies := []SAttachedPolicy{} 99 marker := "" 100 for { 101 part, err := self.client.ListAttachedRolePolicies(self.RoleName, marker, 100, "") 102 if err != nil { 103 return nil, errors.Wrapf(err, "ListAttachedRolePolicies") 104 } 105 policies = append(policies, part.AttachedPolicies...) 106 marker = part.Marker 107 if len(marker) == 0 { 108 break 109 } 110 } 111 ret := []cloudprovider.ICloudpolicy{} 112 for i := range policies { 113 policies[i].client = self.client 114 ret = append(ret, &policies[i]) 115 } 116 return ret, nil 117 } 118 119 type SRoles struct { 120 Roles []SRole `xml:"Roles>member"` 121 IsTruncated bool `xml:"IsTruncated"` 122 Marker string `xml:"Marker"` 123 } 124 125 func (self *SAwsClient) ListRoles(offset string, limit int, prefix string) (*SRoles, error) { 126 if limit < 1 || limit > 1000 { 127 limit = 1000 128 } 129 params := map[string]string{ 130 "MaxItems": fmt.Sprintf("%d", limit), 131 } 132 if len(offset) > 0 { 133 params["Marker"] = offset 134 } 135 if len(prefix) > 0 { 136 params["PathPrefix"] = prefix 137 } 138 roles := &SRoles{} 139 err := self.iamRequest("ListRoles", params, roles) 140 if err != nil { 141 return nil, errors.Wrapf(err, "ListRoles") 142 } 143 return roles, nil 144 } 145 146 func (self *SAwsClient) GetRole(roleName string) (*SRole, error) { 147 params := map[string]string{ 148 "RoleName": roleName, 149 } 150 result := struct { 151 Role SRole `xml:"Role"` 152 }{} 153 err := self.iamRequest("GetRole", params, &result) 154 if err != nil { 155 return nil, errors.Wrap(err, "GetRole") 156 } 157 return &result.Role, nil 158 } 159 160 func (self *SAwsClient) DeleteRole(name string) error { 161 params := map[string]string{ 162 "RoleName": name, 163 } 164 return self.iamRequest("DeleteRole", params, nil) 165 } 166 167 func (self *SAwsClient) GetICloudroles() ([]cloudprovider.ICloudrole, error) { 168 roles := []SRole{} 169 marker := "" 170 for { 171 part, err := self.ListRoles(marker, 100, "") 172 if err != nil { 173 return nil, errors.Wrapf(err, "ListRoles") 174 } 175 roles = append(roles, part.Roles...) 176 marker = part.Marker 177 if len(marker) == 0 { 178 break 179 } 180 } 181 ret := []cloudprovider.ICloudrole{} 182 for i := range roles { 183 roles[i].client = self 184 ret = append(ret, &roles[i]) 185 } 186 return ret, nil 187 } 188 189 func (self *SAwsClient) CreateRole(opts *cloudprovider.SRoleCreateOptions) (*SRole, error) { 190 if len(opts.SAMLProvider) > 0 { 191 aud := "https://signin.amazonaws.cn/saml" 192 if self.GetAccessEnv() == api.CLOUD_ACCESS_ENV_AWS_GLOBAL { 193 aud = "https://signin.aws.amazon.com/saml" 194 } 195 params := map[string]string{ 196 "RoleName": opts.Name, 197 "Description": opts.Desc, 198 "AssumeRolePolicyDocument": fmt.Sprintf(samlRole, opts.SAMLProvider, aud), 199 } 200 role := struct { 201 Role SRole 202 }{} 203 err := self.iamRequest("CreateRole", params, &role) 204 if err != nil { 205 return nil, errors.Wrapf(err, "CreateRole") 206 } 207 role.Role.client = self 208 return &role.Role, nil 209 } 210 return nil, cloudprovider.ErrNotImplemented 211 }