yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/aws/iam_user.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 "time" 20 21 "yunion.io/x/log" 22 "yunion.io/x/pkg/errors" 23 24 "yunion.io/x/cloudmux/pkg/cloudprovider" 25 "yunion.io/x/cloudmux/pkg/multicloud" 26 ) 27 28 type SUsers struct { 29 Users []SUser `xml:"Users>member"` 30 IsTruncated bool `xml:"IsTruncated"` 31 Marker string `xml:"Marker"` 32 } 33 34 type SUser struct { 35 client *SAwsClient 36 multicloud.SBaseClouduser 37 38 UserId string `xml:"UserId"` 39 Path string `xml:"Path"` 40 UserName string `xml:"UserName"` 41 Arn string `xml:"Arn"` 42 CreateDate time.Time `xml:"CreateDate"` 43 PasswordLastUsed time.Time `xml:"PasswordLastUsed"` 44 } 45 46 func (user *SUser) GetEmailAddr() string { 47 return "" 48 } 49 50 func (user *SUser) GetInviteUrl() string { 51 return "" 52 } 53 54 func (user *SUser) AttachSystemPolicy(policyArn string) error { 55 return user.client.AttachUserPolicy(user.UserName, user.client.getIamArn(policyArn)) 56 } 57 58 func (user *SUser) AttachCustomPolicy(policyArn string) error { 59 return user.client.AttachUserPolicy(user.UserName, user.client.getIamArn(policyArn)) 60 } 61 62 func (user *SUser) DetachSystemPolicy(policyArn string) error { 63 return user.client.DetachUserPolicy(user.UserName, user.client.getIamArn(policyArn)) 64 } 65 66 func (user *SUser) DetachCustomPolicy(policyArn string) error { 67 return user.client.DetachUserPolicy(user.UserName, user.client.getIamArn(policyArn)) 68 } 69 70 func (user *SUser) GetGlobalId() string { 71 return user.UserId 72 } 73 74 func (user *SUser) GetName() string { 75 return user.UserName 76 } 77 78 func (user *SUser) ResetPassword(password string) error { 79 return user.client.ResetUserPassword(user.UserName, password) 80 } 81 82 func (user *SUser) IsConsoleLogin() bool { 83 _, err := user.client.GetLoginProfile(user.UserName) 84 if errors.Cause(err) == cloudprovider.ErrNotFound { 85 return false 86 } 87 return true 88 } 89 90 func (user *SUser) GetICloudgroups() ([]cloudprovider.ICloudgroup, error) { 91 groups, err := user.ListGroups() 92 if err != nil { 93 return nil, errors.Wrapf(err, "ListGroups") 94 } 95 ret := []cloudprovider.ICloudgroup{} 96 for i := range groups { 97 groups[i].client = user.client 98 ret = append(ret, &groups[i]) 99 } 100 return ret, nil 101 } 102 103 func (self *SUser) ListPolicies() ([]SAttachedPolicy, error) { 104 policies := []SAttachedPolicy{} 105 offset := "" 106 for { 107 part, err := self.client.ListAttachedUserPolicies(self.UserName, offset, 1000, "") 108 if err != nil { 109 return nil, errors.Wrap(err, "ListAttachedUserPolicies") 110 } 111 for i := range part.AttachedPolicies { 112 part.AttachedPolicies[i].client = self.client 113 policies = append(policies, part.AttachedPolicies[i]) 114 } 115 offset = part.Marker 116 if len(offset) == 0 || !part.IsTruncated { 117 break 118 } 119 } 120 return policies, nil 121 } 122 123 func (self *SUser) GetISystemCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { 124 policies, err := self.ListPolicies() 125 if err != nil { 126 return nil, errors.Wrapf(err, "ListPolicies") 127 } 128 customMaps, err := self.client.GetCustomPolicyMaps() 129 if err != nil { 130 return nil, errors.Wrapf(err, "GetCustomPolicyMaps") 131 } 132 ret := []cloudprovider.ICloudpolicy{} 133 for i := range policies { 134 _, ok := customMaps[policies[i].PolicyName] 135 if !ok { 136 ret = append(ret, &policies[i]) 137 } 138 } 139 return ret, nil 140 } 141 142 func (self *SUser) GetICustomCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { 143 policies, err := self.ListPolicies() 144 if err != nil { 145 return nil, errors.Wrapf(err, "ListPolicies") 146 } 147 customMaps, err := self.client.GetCustomPolicyMaps() 148 if err != nil { 149 return nil, errors.Wrapf(err, "GetCustomPolicyMaps") 150 } 151 ret := []cloudprovider.ICloudpolicy{} 152 for i := range policies { 153 _, ok := customMaps[policies[i].PolicyName] 154 if ok { 155 ret = append(ret, &policies[i]) 156 } 157 } 158 return ret, nil 159 } 160 161 func (user *SUser) ListGroups() ([]SGroup, error) { 162 groups := []SGroup{} 163 offset := "" 164 for { 165 part, err := user.client.ListGroupsForUser(user.UserName, offset, 1000) 166 if err != nil { 167 return nil, errors.Wrap(err, "ListGroupsForUser") 168 } 169 groups = append(groups, part.Groups...) 170 offset = part.Marker 171 if len(offset) == 0 || !part.IsTruncated { 172 break 173 } 174 } 175 return groups, nil 176 } 177 178 func (user *SUser) Delete() error { 179 groups, err := user.ListGroups() 180 if err != nil { 181 return errors.Wrapf(err, "ListGroups") 182 } 183 for _, group := range groups { 184 err = user.client.RemoveUserFromGroup(group.GroupName, user.UserName) 185 if err != nil { 186 return errors.Wrap(err, "RemoveUserFromGroup") 187 } 188 } 189 policies, err := user.ListPolicies() 190 if err != nil { 191 return errors.Wrapf(err, "ListPolicies") 192 } 193 for _, policy := range policies { 194 err = user.client.DetachUserPolicy(user.UserName, policy.PolicyArn) 195 if err != nil { 196 return errors.Wrap(err, "DetachPolicy") 197 } 198 } 199 return user.client.DeleteUser(user.UserName) 200 } 201 202 func (self *SAwsClient) ListUsers(offset string, limit int, pathPrefix string) (*SUsers, error) { 203 if limit <= 0 || limit > 1000 { 204 limit = 1000 205 } 206 params := map[string]string{ 207 "MaxItems": fmt.Sprintf("%d", limit), 208 } 209 if len(offset) > 0 { 210 params["Marker"] = offset 211 } 212 if len(pathPrefix) > 0 { 213 params["PathPrefix"] = pathPrefix 214 } 215 users := &SUsers{} 216 err := self.iamRequest("ListUsers", params, users) 217 if err != nil { 218 return nil, errors.Wrap(err, "iamRequest.ListUsers") 219 } 220 return users, nil 221 } 222 223 func (self *SAwsClient) CreateUser(path string, username string) (*SUser, error) { 224 params := map[string]string{ 225 "UserName": username, 226 } 227 if len(path) > 0 { 228 params["Path"] = path 229 } 230 user := struct { 231 User SUser `xml:"User"` 232 }{} 233 err := self.iamRequest("CreateUser", params, &user) 234 if err != nil { 235 return nil, errors.Wrap(err, "iamRequest.CreateUser") 236 } 237 user.User.client = self 238 return &user.User, nil 239 } 240 241 func (self *SAwsClient) DeleteUser(name string) error { 242 self.DeleteLoginProfile(name) 243 params := map[string]string{ 244 "UserName": name, 245 } 246 return self.iamRequest("DeleteUser", params, nil) 247 } 248 249 func (self *SAwsClient) AttachUserPolicy(userName string, policyArn string) error { 250 params := map[string]string{ 251 "PolicyArn": policyArn, 252 "UserName": userName, 253 } 254 return self.iamRequest("AttachUserPolicy", params, nil) 255 } 256 257 func (self *SAwsClient) DetachUserPolicy(userName string, policyArn string) error { 258 params := map[string]string{ 259 "PolicyArn": policyArn, 260 "UserName": userName, 261 } 262 err := self.iamRequest("DetachUserPolicy", params, nil) 263 if err != nil && errors.Cause(err) != cloudprovider.ErrNotFound { 264 return errors.Wrap(err, "DetachUserPolicy") 265 } 266 return nil 267 } 268 269 func (self *SAwsClient) CreateIClouduser(conf *cloudprovider.SClouduserCreateConfig) (cloudprovider.IClouduser, error) { 270 user, err := self.CreateUser("", conf.Name) 271 if err != nil { 272 return nil, errors.Wrap(err, "CreateUser") 273 } 274 if len(conf.Password) > 0 { 275 _, err := self.CreateLoginProfile(conf.Name, conf.Password) 276 if err != nil { 277 log.Errorf("failed to create loginProfile for user %s error: %v", conf.Name, err) 278 } 279 } 280 return user, nil 281 } 282 283 func (self *SAwsClient) GetIClouduserByName(name string) (cloudprovider.IClouduser, error) { 284 return self.GetUser(name) 285 } 286 287 func (self *SAwsClient) GetUser(name string) (*SUser, error) { 288 user := struct { 289 User SUser `xml:"User"` 290 }{} 291 params := map[string]string{ 292 "UserName": name, 293 } 294 err := self.iamRequest("GetUser", params, &user) 295 if err != nil { 296 return nil, errors.Wrap(err, "iamRequest.GetUser") 297 } 298 user.User.client = self 299 return &user.User, nil 300 } 301 302 func (self *SAwsClient) GetICloudusers() ([]cloudprovider.IClouduser, error) { 303 ret := []cloudprovider.IClouduser{} 304 offset := "" 305 for { 306 part, err := self.ListUsers(offset, 1000, "") 307 if err != nil { 308 return nil, errors.Wrap(err, "ListUsers") 309 } 310 for i := range part.Users { 311 part.Users[i].client = self 312 ret = append(ret, &part.Users[i]) 313 } 314 offset = part.Marker 315 if len(offset) == 0 || !part.IsTruncated { 316 break 317 } 318 } 319 return ret, nil 320 } 321 322 type LoginProfile struct { 323 UserName string `xml:"UserName"` 324 CreateDate time.Time `xml:"CreateDate"` 325 } 326 type SLoginProfile struct { 327 LoginProfile LoginProfile `xml:"LoginProfile"` 328 } 329 330 func (self *SAwsClient) GetLoginProfile(name string) (*SLoginProfile, error) { 331 params := map[string]string{ 332 "UserName": name, 333 } 334 loginProfix := &SLoginProfile{} 335 err := self.iamRequest("GetLoginProfile", params, loginProfix) 336 if err != nil { 337 return nil, errors.Wrap(err, "iamRequest.GetLoginProfie") 338 } 339 return loginProfix, nil 340 } 341 342 func (self *SAwsClient) DeleteLoginProfile(name string) error { 343 params := map[string]string{ 344 "UserName": name, 345 } 346 return self.iamRequest("DeleteLoginProfile", params, nil) 347 } 348 349 func (self *SAwsClient) CreateLoginProfile(name, password string) (*SLoginProfile, error) { 350 params := map[string]string{ 351 "UserName": name, 352 "Password": password, 353 } 354 loginProfile := &SLoginProfile{} 355 err := self.iamRequest("CreateLoginProfile", params, loginProfile) 356 if err != nil { 357 return nil, errors.Wrap(err, "iamRequest.GetLoginProfie") 358 } 359 return loginProfile, nil 360 } 361 362 func (self *SAwsClient) UpdateLoginProfile(name, password string) error { 363 params := map[string]string{ 364 "UserName": name, 365 "Password": password, 366 } 367 return self.iamRequest("UpdateLoginProfile", params, nil) 368 } 369 370 func (self *SAwsClient) ResetUserPassword(name, password string) error { 371 _, err := self.GetLoginProfile(name) 372 if err != nil { 373 if errors.Cause(err) == cloudprovider.ErrNotFound { 374 _, err = self.CreateLoginProfile(name, password) 375 return err 376 } 377 return errors.Wrap(err, "GetLoginProfile") 378 } 379 return self.UpdateLoginProfile(name, password) 380 } 381 382 func (self *SAwsClient) ListGroupsForUser(name string, offset string, limit int) (*SGroups, error) { 383 if limit < 1 || limit > 1000 { 384 limit = 1000 385 } 386 params := map[string]string{ 387 "UserName": name, 388 "MaxItems": fmt.Sprintf("%d", limit), 389 } 390 if len(offset) > 0 { 391 params["Marker"] = offset 392 } 393 groups := &SGroups{} 394 err := self.iamRequest("ListGroupsForUser", params, groups) 395 if err != nil { 396 return nil, errors.Wrap(err, "ListGroupsForUser") 397 } 398 return groups, nil 399 }