yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/apsara/securitygroup.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 apsara 16 17 import ( 18 "fmt" 19 "strings" 20 "time" 21 22 "yunion.io/x/jsonutils" 23 "yunion.io/x/log" 24 "yunion.io/x/pkg/errors" 25 "yunion.io/x/pkg/util/secrules" 26 "yunion.io/x/pkg/utils" 27 28 "yunion.io/x/cloudmux/pkg/cloudprovider" 29 "yunion.io/x/cloudmux/pkg/multicloud" 30 ) 31 32 // {"CreationTime":"2017-03-19T13:37:48Z","Description":"System created security group.","SecurityGroupId":"sg-j6cannq0xxj2r9z0yxwl","SecurityGroupName":"sg-j6cannq0xxj2r9z0yxwl","Tags":{"Tag":[]},"VpcId":"vpc-j6c86z3sh8ufhgsxwme0q"} 33 // {"Description":"System created security group.","InnerAccessPolicy":"Accept","Permissions":{"Permission":[{"CreateTime":"2017-03-19T13:37:54Z","Description":"","DestCidrIp":"","DestGroupId":"","DestGroupName":"","DestGroupOwnerAccount":"","Direction":"ingress","IpProtocol":"ALL","NicType":"intranet","Policy":"Accept","PortRange":"-1/-1","Priority":110,"SourceCidrIp":"0.0.0.0/0","SourceGroupId":"","SourceGroupName":"","SourceGroupOwnerAccount":""},{"CreateTime":"2017-03-19T13:37:55Z","Description":"","DestCidrIp":"0.0.0.0/0","DestGroupId":"","DestGroupName":"","DestGroupOwnerAccount":"","Direction":"egress","IpProtocol":"ALL","NicType":"intranet","Policy":"Accept","PortRange":"-1/-1","Priority":110,"SourceCidrIp":"","SourceGroupId":"","SourceGroupName":"","SourceGroupOwnerAccount":""}]},"RegionId":"cn-hongkong","RequestId":"FBFE0950-5F2D-40DE-8C3C-E5A62AE7F7DA","SecurityGroupId":"sg-j6cannq0xxj2r9z0yxwl","SecurityGroupName":"sg-j6cannq0xxj2r9z0yxwl","VpcId":"vpc-j6c86z3sh8ufhgsxwme0q"} 34 35 type SecurityGroupPermissionNicType string 36 37 const ( 38 IntranetNicType SecurityGroupPermissionNicType = "intranet" 39 InternetNicType SecurityGroupPermissionNicType = "internet" 40 ) 41 42 type SPermission struct { 43 CreateTime time.Time 44 Description string 45 DestCidrIp string 46 DestGroupId string 47 DestGroupName string 48 DestGroupOwnerAccount string 49 Direction string 50 IpProtocol string 51 NicType SecurityGroupPermissionNicType 52 Policy string 53 PortRange string 54 Priority int 55 SourceCidrIp string 56 SourceGroupId string 57 SourceGroupName string 58 SourceGroupOwnerAccount string 59 } 60 61 type SPermissions struct { 62 Permission []SPermission 63 } 64 65 type Tags struct { 66 Tag []Tag 67 } 68 69 type Tag struct { 70 TagKey string 71 TagValue string 72 } 73 74 type SSecurityGroup struct { 75 multicloud.SSecurityGroup 76 ApsaraTags 77 78 vpc *SVpc 79 CreationTime time.Time 80 Description string 81 SecurityGroupId string 82 SecurityGroupName string 83 VpcId string 84 InnerAccessPolicy string 85 Permissions SPermissions 86 RegionId string 87 Tags Tags 88 89 DepartmentInfo 90 } 91 92 func (self *SSecurityGroup) GetVpcId() string { 93 return self.VpcId 94 } 95 96 func (self *SSecurityGroup) GetTags() (map[string]string, error) { 97 tags := map[string]string{} 98 for _, value := range self.Tags.Tag { 99 tags[value.TagKey] = value.TagValue 100 } 101 return tags, nil 102 } 103 104 func (self *SSecurityGroup) GetId() string { 105 return self.SecurityGroupId 106 } 107 108 func (self *SSecurityGroup) GetGlobalId() string { 109 return self.SecurityGroupId 110 } 111 112 func (self *SSecurityGroup) GetDescription() string { 113 return self.Description 114 } 115 116 func (self *SSecurityGroup) GetCreatedAt() time.Time { 117 return self.CreationTime 118 } 119 120 func (self *SSecurityGroup) GetRules() ([]cloudprovider.SecurityRule, error) { 121 rules := make([]cloudprovider.SecurityRule, 0) 122 secgrp, err := self.vpc.region.GetSecurityGroupDetails(self.SecurityGroupId) 123 if err != nil { 124 return nil, err 125 } 126 for _, permission := range secgrp.Permissions.Permission { 127 rule, err := permission.toRule() 128 if err != nil { 129 log.Errorf("convert rule %s for group %s(%s) error: %v", permission.Description, self.SecurityGroupName, self.SecurityGroupId, err) 130 continue 131 } 132 rules = append(rules, rule) 133 } 134 return rules, nil 135 } 136 137 func (self *SSecurityGroup) GetName() string { 138 if len(self.SecurityGroupName) > 0 { 139 return self.SecurityGroupName 140 } 141 return self.SecurityGroupId 142 } 143 144 func (self *SSecurityGroup) GetStatus() string { 145 return "" 146 } 147 148 func (self *SSecurityGroup) IsEmulated() bool { 149 return false 150 } 151 152 func (self *SSecurityGroup) Refresh() error { 153 group, err := self.vpc.region.GetSecurityGroupDetails(self.SecurityGroupId) 154 if err != nil { 155 return err 156 } 157 return jsonutils.Update(self, group) 158 } 159 160 func (self *SRegion) GetSecurityGroups(vpcId, name string, securityGroupIds []string, offset int, limit int) ([]SSecurityGroup, int, error) { 161 if limit > 50 || limit <= 0 { 162 limit = 50 163 } 164 params := make(map[string]string) 165 params["RegionId"] = self.RegionId 166 params["PageSize"] = fmt.Sprintf("%d", limit) 167 params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) 168 if len(vpcId) > 0 { 169 params["VpcId"] = vpcId 170 } 171 if len(name) > 0 { 172 params["SecurityGroupName"] = name 173 } 174 175 if securityGroupIds != nil && len(securityGroupIds) > 0 { 176 params["SecurityGroupIds"] = jsonutils.Marshal(securityGroupIds).String() 177 } 178 179 body, err := self.ecsRequest("DescribeSecurityGroups", params) 180 if err != nil { 181 log.Errorf("GetSecurityGroups fail %s", err) 182 return nil, 0, err 183 } 184 185 secgrps := make([]SSecurityGroup, 0) 186 err = body.Unmarshal(&secgrps, "SecurityGroups", "SecurityGroup") 187 if err != nil { 188 log.Errorf("Unmarshal security groups fail %s", err) 189 return nil, 0, err 190 } 191 total, _ := body.Int("TotalCount") 192 return secgrps, int(total), nil 193 } 194 195 func (self *SRegion) GetSecurityGroupDetails(secGroupId string) (*SSecurityGroup, error) { 196 params := make(map[string]string) 197 params["RegionId"] = self.RegionId 198 params["SecurityGroupId"] = secGroupId 199 200 body, err := self.ecsRequest("DescribeSecurityGroupAttribute", params) 201 if err != nil { 202 return nil, errors.Wrap(err, "DescribeSecurityGroupAttribute") 203 } 204 205 secgrp := SSecurityGroup{} 206 err = body.Unmarshal(&secgrp) 207 if err != nil { 208 return nil, errors.Wrap(err, "body.Unmarshal") 209 } 210 return &secgrp, nil 211 } 212 213 func (self *SRegion) CreateSecurityGroup(vpcId string, name string, desc string) (string, error) { 214 params := make(map[string]string) 215 if len(vpcId) > 0 { 216 params["VpcId"] = vpcId 217 } 218 219 if name == "Default" { 220 name = "Default-copy" 221 } 222 223 if len(name) > 0 { 224 params["SecurityGroupName"] = name 225 } 226 if len(desc) > 0 { 227 params["Description"] = desc 228 } 229 params["ClientToken"] = utils.GenRequestId(20) 230 231 body, err := self.ecsRequest("CreateSecurityGroup", params) 232 if err != nil { 233 return "", errors.Wrap(err, "CreateSecurityGroup") 234 } 235 return body.GetString("SecurityGroupId") 236 } 237 238 func (self *SRegion) modifySecurityGroupRule(secGrpId string, rule *secrules.SecurityRule) error { 239 params := make(map[string]string) 240 params["RegionId"] = self.RegionId 241 params["SecurityGroupId"] = secGrpId 242 params["NicType"] = string(IntranetNicType) 243 params["Description"] = rule.Description 244 params["PortRange"] = fmt.Sprintf("%d/%d", rule.PortStart, rule.PortEnd) 245 protocol := rule.Protocol 246 if len(rule.Protocol) == 0 || rule.Protocol == secrules.PROTO_ANY { 247 protocol = "all" 248 } 249 params["IpProtocol"] = protocol 250 if rule.PortStart < 1 && rule.PortEnd < 1 { 251 if protocol == "udp" || protocol == "tcp" { 252 params["PortRange"] = "1/65535" 253 } else { 254 params["PortRange"] = "-1/-1" 255 } 256 } 257 if rule.Action == secrules.SecurityRuleAllow { 258 params["Policy"] = "accept" 259 } else { 260 params["Policy"] = "drop" 261 } 262 params["Priority"] = fmt.Sprintf("%d", rule.Priority) 263 if rule.Direction == secrules.SecurityRuleIngress { 264 if rule.IPNet != nil { 265 params["SourceCidrIp"] = rule.IPNet.String() 266 } else { 267 params["SourceCidrIp"] = "0.0.0.0/0" 268 } 269 _, err := self.ecsRequest("ModifySecurityGroupRule", params) 270 return err 271 } else { // rule.Direction == secrules.SecurityRuleEgress { 272 //阿里云不支持出方向API接口调用 273 return nil 274 // if rule.IPNet != nil { 275 // params["DestCidrIp"] = rule.IPNet.String() 276 // } else { 277 // params["DestCidrIp"] = "0.0.0.0/0" 278 // } 279 // _, err := self.ecsRequest("ModifySecurityGroupRule", params) 280 // return err 281 } 282 } 283 284 func (self *SRegion) modifySecurityGroup(secGrpId string, name string, desc string) error { 285 params := make(map[string]string) 286 params["RegionId"] = self.RegionId 287 params["SecurityGroupId"] = secGrpId 288 params["SecurityGroupName"] = name 289 if len(desc) > 0 { 290 params["Description"] = desc 291 } 292 _, err := self.ecsRequest("ModifySecurityGroupAttribute", params) 293 return err 294 } 295 296 func (self *SRegion) AddSecurityGroupRules(secGrpId string, rule secrules.SecurityRule) error { 297 if len(rule.Ports) != 0 { 298 for _, port := range rule.Ports { 299 rule.PortStart, rule.PortEnd = port, port 300 err := self.addSecurityGroupRule(secGrpId, rule) 301 if err != nil { 302 return errors.Wrapf(err, "addSecurityGroupRule %s", rule.String()) 303 } 304 } 305 return nil 306 } 307 return self.addSecurityGroupRule(secGrpId, rule) 308 } 309 310 func (self *SRegion) addSecurityGroupRule(secGrpId string, rule secrules.SecurityRule) error { 311 params := make(map[string]string) 312 params["RegionId"] = self.RegionId 313 params["SecurityGroupId"] = secGrpId 314 params["NicType"] = string(IntranetNicType) 315 params["Description"] = rule.Description 316 params["PortRange"] = fmt.Sprintf("%d/%d", rule.PortStart, rule.PortEnd) 317 protocol := rule.Protocol 318 if len(rule.Protocol) == 0 || rule.Protocol == secrules.PROTO_ANY { 319 protocol = "all" 320 } 321 params["IpProtocol"] = protocol 322 if rule.PortStart < 1 && rule.PortEnd < 1 { 323 if protocol == "udp" || protocol == "tcp" { 324 params["PortRange"] = "1/65535" 325 } else { 326 params["PortRange"] = "-1/-1" 327 } 328 } 329 if rule.Action == secrules.SecurityRuleAllow { 330 params["Policy"] = "accept" 331 } else { 332 params["Policy"] = "drop" 333 } 334 335 // 忽略地址为0.0.0.0/32这样的阿里云规则 336 if rule.IPNet.IP.String() == "0.0.0.0" && rule.IPNet.String() != "0.0.0.0/0" { 337 return nil 338 } 339 340 params["Priority"] = fmt.Sprintf("%d", rule.Priority) 341 if rule.Direction == secrules.SecurityRuleIngress { 342 if rule.IPNet != nil { 343 params["SourceCidrIp"] = rule.IPNet.String() 344 } else { 345 params["SourceCidrIp"] = "0.0.0.0/0" 346 } 347 _, err := self.ecsRequest("AuthorizeSecurityGroup", params) 348 return err 349 } else { // rule.Direction == secrules.SecurityRuleEgress { 350 if rule.IPNet != nil { 351 params["DestCidrIp"] = rule.IPNet.String() 352 } else { 353 params["DestCidrIp"] = "0.0.0.0/0" 354 } 355 _, err := self.ecsRequest("AuthorizeSecurityGroupEgress", params) 356 return err 357 } 358 } 359 360 func (self *SRegion) DelSecurityGroupRule(secGrpId string, rule secrules.SecurityRule) error { 361 params := make(map[string]string) 362 params["RegionId"] = self.RegionId 363 params["SecurityGroupId"] = secGrpId 364 params["NicType"] = string(IntranetNicType) 365 params["PortRange"] = fmt.Sprintf("%d/%d", rule.PortStart, rule.PortEnd) 366 protocol := rule.Protocol 367 if len(rule.Protocol) == 0 || rule.Protocol == secrules.PROTO_ANY { 368 protocol = "all" 369 } 370 params["IpProtocol"] = protocol 371 if rule.PortStart < 1 && rule.PortEnd < 1 { 372 if protocol == "udp" || protocol == "tcp" { 373 params["PortRange"] = "1/65535" 374 } else { 375 params["PortRange"] = "-1/-1" 376 } 377 } 378 if rule.Action == secrules.SecurityRuleAllow { 379 params["Policy"] = "accept" 380 } else { 381 params["Policy"] = "drop" 382 } 383 params["Priority"] = fmt.Sprintf("%d", rule.Priority) 384 if rule.Direction == secrules.SecurityRuleIngress { 385 if rule.IPNet != nil { 386 params["SourceCidrIp"] = rule.IPNet.String() 387 } else { 388 params["SourceCidrIp"] = "0.0.0.0/0" 389 } 390 _, err := self.ecsRequest("RevokeSecurityGroup", params) 391 return err 392 } else { // rule.Direction == secrules.SecurityRuleEgress { 393 if rule.IPNet != nil { 394 params["DestCidrIp"] = rule.IPNet.String() 395 } else { 396 params["DestCidrIp"] = "0.0.0.0/0" 397 } 398 _, err := self.ecsRequest("RevokeSecurityGroupEgress", params) 399 return err 400 } 401 } 402 403 func (self *SPermission) toRule() (cloudprovider.SecurityRule, error) { 404 rule := cloudprovider.SecurityRule{ 405 SecurityRule: secrules.SecurityRule{ 406 Action: secrules.SecurityRuleDeny, 407 Direction: secrules.DIR_IN, 408 Priority: self.Priority, 409 Description: self.Description, 410 PortStart: -1, 411 PortEnd: -1, 412 }, 413 } 414 if strings.ToLower(self.Policy) == "accept" { 415 rule.Action = secrules.SecurityRuleAllow 416 } 417 418 cidr := self.SourceCidrIp 419 if self.Direction == "egress" { 420 rule.Direction = secrules.DIR_OUT 421 cidr = self.DestCidrIp 422 } 423 424 rule.ParseCIDR(cidr) 425 426 switch strings.ToLower(self.IpProtocol) { 427 case "tcp", "udp", "icmp": 428 rule.Protocol = strings.ToLower(self.IpProtocol) 429 case "all": 430 rule.Protocol = secrules.PROTO_ANY 431 default: 432 return rule, fmt.Errorf("unsupported protocal %s", self.IpProtocol) 433 } 434 435 port, ports := "", strings.Split(self.PortRange, "/") 436 if ports[0] == ports[1] { 437 if ports[0] != "-1" { 438 port = ports[0] 439 } 440 } else if ports[0] != "1" && ports[1] != "65535" { 441 port = fmt.Sprintf("%s-%s", ports[0], ports[1]) 442 } 443 err := rule.ParsePorts(port) 444 if err != nil { 445 return rule, errors.Wrapf(err, "ParsePorts(%s)", port) 446 } 447 return rule, nil 448 } 449 450 func (self *SRegion) AssignSecurityGroup(secgroupId, instanceId string) error { 451 return self.SetSecurityGroups([]string{secgroupId}, instanceId) 452 } 453 454 func (self *SRegion) SetSecurityGroups(secgroupIds []string, instanceId string) error { 455 params := map[string]string{"InstanceId": instanceId} 456 for _, secgroupId := range secgroupIds { 457 params["SecurityGroupId"] = secgroupId 458 if _, err := self.ecsRequest("JoinSecurityGroup", params); err != nil { 459 return err 460 } 461 } 462 instance, err := self.GetInstance(instanceId) 463 if err != nil { 464 return err 465 } 466 for _, _secgroupId := range instance.SecurityGroupIds.SecurityGroupId { 467 if !utils.IsInStringArray(_secgroupId, secgroupIds) { 468 if err := self.leaveSecurityGroup(_secgroupId, instanceId); err != nil { 469 return err 470 } 471 } 472 } 473 return nil 474 } 475 476 func (self *SRegion) leaveSecurityGroup(secgroupId, instanceId string) error { 477 params := map[string]string{"InstanceId": instanceId, "SecurityGroupId": secgroupId} 478 _, err := self.ecsRequest("LeaveSecurityGroup", params) 479 return err 480 } 481 482 func (self *SRegion) DeleteSecurityGroup(secGrpId string) error { 483 params := make(map[string]string) 484 params["SecurityGroupId"] = secGrpId 485 486 _, err := self.ecsRequest("DeleteSecurityGroup", params) 487 if err != nil { 488 log.Errorf("Delete security group fail %s", err) 489 return err 490 } 491 return nil 492 } 493 494 func (self *SSecurityGroup) Delete() error { 495 return self.vpc.region.DeleteSecurityGroup(self.SecurityGroupId) 496 } 497 498 func (self *SSecurityGroup) SyncRules(common, inAdds, outAdds, inDels, outDels []cloudprovider.SecurityRule) error { 499 for _, rule := range append(inDels, outDels...) { 500 err := self.vpc.region.DelSecurityGroupRule(self.SecurityGroupId, rule.SecurityRule) 501 if err != nil { 502 return errors.Wrapf(err, "DelSecurityGroupRule(Name:%s priority: %d %s)", rule.Name, rule.Priority, rule.String()) 503 } 504 } 505 for _, rule := range append(inAdds, outAdds...) { 506 err := self.vpc.region.AddSecurityGroupRules(self.SecurityGroupId, rule.SecurityRule) 507 if err != nil { 508 return errors.Wrapf(err, "AddSecurityGroupRules(priority: %d %s)", rule.Priority, rule.String()) 509 } 510 } 511 return nil 512 }