cloud-mu 3.1.4 → 3.1.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/ansible/roles/mu-windows/README.md +33 -0
- data/ansible/roles/mu-windows/defaults/main.yml +2 -0
- data/ansible/roles/mu-windows/handlers/main.yml +2 -0
- data/ansible/roles/mu-windows/meta/main.yml +53 -0
- data/ansible/roles/mu-windows/tasks/main.yml +20 -0
- data/ansible/roles/mu-windows/tests/inventory +2 -0
- data/ansible/roles/mu-windows/tests/test.yml +5 -0
- data/ansible/roles/mu-windows/vars/main.yml +2 -0
- data/cloud-mu.gemspec +4 -2
- data/cookbooks/mu-tools/recipes/selinux.rb +2 -1
- data/cookbooks/mu-tools/recipes/windows-client.rb +140 -144
- data/cookbooks/mu-tools/resources/windows_users.rb +44 -43
- data/extras/image-generators/AWS/win2k12.yaml +16 -13
- data/extras/image-generators/AWS/win2k16.yaml +16 -13
- data/extras/image-generators/AWS/win2k19.yaml +19 -0
- data/modules/mu.rb +72 -9
- data/modules/mu/adoption.rb +14 -2
- data/modules/mu/cloud.rb +111 -10
- data/modules/mu/clouds/aws.rb +23 -7
- data/modules/mu/clouds/aws/container_cluster.rb +640 -692
- data/modules/mu/clouds/aws/dnszone.rb +49 -45
- data/modules/mu/clouds/aws/firewall_rule.rb +177 -214
- data/modules/mu/clouds/aws/role.rb +17 -8
- data/modules/mu/clouds/aws/search_domain.rb +1 -1
- data/modules/mu/clouds/aws/server.rb +734 -1027
- data/modules/mu/clouds/aws/userdata/windows.erb +2 -1
- data/modules/mu/clouds/aws/vpc.rb +297 -786
- data/modules/mu/clouds/aws/vpc_subnet.rb +286 -0
- data/modules/mu/clouds/google/bucket.rb +1 -1
- data/modules/mu/clouds/google/container_cluster.rb +21 -17
- data/modules/mu/clouds/google/function.rb +8 -2
- data/modules/mu/clouds/google/server.rb +102 -32
- data/modules/mu/clouds/google/vpc.rb +1 -1
- data/modules/mu/config.rb +12 -1
- data/modules/mu/config/server.yml +1 -0
- data/modules/mu/defaults/AWS.yaml +51 -28
- data/modules/mu/groomers/ansible.rb +54 -17
- data/modules/mu/groomers/chef.rb +13 -7
- data/modules/mu/master/ssl.rb +0 -1
- data/modules/mu/mommacat.rb +8 -0
- data/modules/tests/ecs.yaml +23 -0
- data/modules/tests/includes-and-params.yaml +2 -1
- data/modules/tests/server-with-scrub-muisms.yaml +1 -0
- data/modules/tests/win2k12.yaml +25 -0
- data/modules/tests/win2k16.yaml +25 -0
- data/modules/tests/win2k19.yaml +25 -0
- data/requirements.txt +1 -0
- metadata +50 -4
- data/extras/image-generators/AWS/windows.yaml +0 -18
- data/modules/tests/needwork/win2k12.yaml +0 -13
@@ -369,7 +369,7 @@ module MU
|
|
369
369
|
def self.manageRecord(id, name, type, targets: nil,
|
370
370
|
ttl: 7200, delete: false, sync_wait: true, failover: nil,
|
371
371
|
healthcheck: nil, region: nil, weight: nil, overwrite: true,
|
372
|
-
location: nil, set_identifier: nil, alias_zone: nil)
|
372
|
+
location: nil, set_identifier: nil, alias_zone: nil, noop: false)
|
373
373
|
|
374
374
|
MU.setVar("curRegion", region) if !region.nil?
|
375
375
|
zone = MU::Cloud::DNSZone.find(cloud_id: id).values.first
|
@@ -380,6 +380,11 @@ module MU
|
|
380
380
|
action = "UPSERT" if overwrite
|
381
381
|
action = "DELETE" if delete
|
382
382
|
|
383
|
+
record_sets = MU::Cloud::AWS.route53.list_resource_record_sets(
|
384
|
+
hosted_zone_id: id,
|
385
|
+
start_record_name: name
|
386
|
+
).resource_record_sets if delete
|
387
|
+
|
383
388
|
if type == "R53ALIAS"
|
384
389
|
target_zone = id
|
385
390
|
target_name = targets[0].downcase
|
@@ -413,7 +418,15 @@ module MU
|
|
413
418
|
}
|
414
419
|
else
|
415
420
|
rrsets = []
|
416
|
-
if
|
421
|
+
if delete
|
422
|
+
record_sets.each { |r|
|
423
|
+
if r.name == name and r.type == type
|
424
|
+
rrsets = MU.structToHash(r.resource_records)
|
425
|
+
end
|
426
|
+
}
|
427
|
+
end
|
428
|
+
|
429
|
+
if !targets.nil? and (!delete or rrsets.empty?)
|
417
430
|
targets.each { |target|
|
418
431
|
rrsets << {value: target}
|
419
432
|
}
|
@@ -426,6 +439,7 @@ module MU
|
|
426
439
|
resource_records: rrsets
|
427
440
|
}
|
428
441
|
|
442
|
+
|
429
443
|
if !healthcheck.nil?
|
430
444
|
base_rrset[:health_check_id] = healthcheck
|
431
445
|
end
|
@@ -445,12 +459,13 @@ module MU
|
|
445
459
|
|
446
460
|
# Doing an UPSERT with a new set_identifier will fail with a record already exist error, so lets try and get it from an existing record.
|
447
461
|
# This can be an issue with multiple secondary failover records
|
448
|
-
if (location || failover || region || weight)
|
449
|
-
record_sets
|
462
|
+
if (location || failover || region || weight) and set_identifier.nil?
|
463
|
+
record_sets ||= MU::Cloud::AWS.route53.list_resource_record_sets(
|
450
464
|
hosted_zone_id: id,
|
451
465
|
start_record_name: name
|
452
466
|
).resource_record_sets
|
453
467
|
|
468
|
+
|
454
469
|
record_sets.each { |r|
|
455
470
|
if r.name == name
|
456
471
|
if location && location == r.location
|
@@ -497,18 +512,23 @@ module MU
|
|
497
512
|
MU.log "Adding DNS record #{name} => #{targets} (#{type}) to #{id}", details: params
|
498
513
|
end
|
499
514
|
|
500
|
-
|
515
|
+
return if noop
|
516
|
+
|
517
|
+
on_retry = Proc.new { |e|
|
518
|
+
if (delete and e.message.match(/but it was not found/)) or
|
519
|
+
(!delete and e.message.match(/(it|name) already exists/))
|
520
|
+
MU.log e.message, MU::DEBUG, details: params
|
521
|
+
return
|
522
|
+
elsif e.class == Aws::Route53::Errors::InvalidChangeBatch
|
523
|
+
MU.log "Problem managing entry for #{name}", MU::ERR, details: params
|
524
|
+
raise MuError, e.inspect
|
525
|
+
end
|
526
|
+
}
|
527
|
+
|
528
|
+
change_id = nil
|
529
|
+
MU.retrier([Aws::Route53::Errors::PriorRequestNotComplete, Aws::Route53::Errors::InvalidChangeBatch], wait: 15, max: 10, on_retry: on_retry) {
|
501
530
|
change_id = MU::Cloud::AWS.route53.change_resource_record_sets(params).change_info.id
|
502
|
-
|
503
|
-
sleep 10
|
504
|
-
retry
|
505
|
-
rescue Aws::Route53::Errors::InvalidChangeBatch, Aws::Route53::Errors::InvalidInput, StandardError => e
|
506
|
-
return if e.message.match(/ but it already exists/) and !delete
|
507
|
-
MU.log "Failed to change DNS records, #{e.inspect}", MU::ERR, details: params
|
508
|
-
raise e if !delete
|
509
|
-
MU.log "Record #{name} (#{type}) in #{id} can't be deleted. Already removed? #{e.inspect}", MU::WARN, details: params if delete
|
510
|
-
return
|
511
|
-
end
|
531
|
+
}
|
512
532
|
|
513
533
|
if sync_wait
|
514
534
|
attempts = 0
|
@@ -535,23 +555,27 @@ module MU
|
|
535
555
|
# @param delete [Boolean]: Remove this entry instead of creating it.
|
536
556
|
# @param cloudclass [Object]: The resource's Mu class.
|
537
557
|
# @param sync_wait [Boolean]: Wait for DNS entry to propagate across zone.
|
538
|
-
def self.genericMuDNSEntry(name: nil, target: nil, cloudclass: nil, noop: false, delete: false, sync_wait: true)
|
539
|
-
return nil if name.nil? or
|
540
|
-
|
558
|
+
def self.genericMuDNSEntry(name: nil, target: nil, cloudclass: nil, noop: false, delete: false, sync_wait: true, credentials: nil)
|
559
|
+
return nil if name.nil? or cloudclass.nil?
|
560
|
+
return nil if target.nil? and !delete
|
561
|
+
mu_zone = MU::Cloud::DNSZone.find(cloud_id: "platform-mu", credentials: credentials).values.first
|
541
562
|
raise MuError, "Couldn't isolate platform-mu DNS zone" if mu_zone.nil?
|
542
563
|
|
543
564
|
if !mu_zone.nil? and !MU.myVPC.nil?
|
544
565
|
subdomain = cloudclass.cfg_name
|
545
566
|
dns_name = name.downcase+"."+subdomain
|
546
567
|
dns_name += "."+MU.myInstanceId if MU.myInstanceId
|
568
|
+
|
547
569
|
record_type = "CNAME"
|
548
570
|
record_type = "A" if target.match(/^\d+\.\d+\.\d+\.\d+/)
|
549
571
|
ip = nil
|
550
572
|
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
573
|
+
records = []
|
574
|
+
lookup = MU::Cloud::AWS.route53(credentials: credentials).list_resource_record_sets(
|
575
|
+
hosted_zone_id: mu_zone.id,
|
576
|
+
start_record_name: "#{dns_name}.platform-mu",
|
577
|
+
start_record_type: record_type,
|
578
|
+
max_items: 1
|
555
579
|
).resource_record_sets
|
556
580
|
|
557
581
|
lookup.each { |record|
|
@@ -572,34 +596,14 @@ module MU
|
|
572
596
|
# MU.log "'#{dns_name}.platform-mu' does not resolve.", MU::DEBUG, details: e.inspect
|
573
597
|
# end
|
574
598
|
|
575
|
-
if ip == target
|
576
|
-
return "#{dns_name}.platform-mu"
|
577
|
-
elsif noop
|
578
|
-
return nil
|
599
|
+
if ip == target and !delete
|
600
|
+
return "#{dns_name}.platform-mu"
|
579
601
|
end
|
580
602
|
|
581
603
|
sync_wait = false if delete
|
582
604
|
|
583
605
|
record_type = "R53ALIAS" if cloudclass == MU::Cloud::AWS::LoadBalancer
|
584
|
-
|
585
|
-
begin
|
586
|
-
MU::Cloud::AWS::DNSZone.manageRecord(mu_zone.id, dns_name, record_type, targets: [target], delete: delete, sync_wait: sync_wait)
|
587
|
-
rescue Aws::Route53::Errors::PriorRequestNotComplete => e
|
588
|
-
MU.log "Route53 was still processing a request, waiting", MU::WARN, details: e
|
589
|
-
sleep 15
|
590
|
-
retry
|
591
|
-
rescue Aws::Route53::Errors::InvalidChangeBatch => e
|
592
|
-
if e.inspect.match(/alias target name does not lie within the target zone/) and attempts < 5
|
593
|
-
MU.log e.inspect, MU::WARN
|
594
|
-
sleep 15
|
595
|
-
attempts = attempts + 1
|
596
|
-
retry
|
597
|
-
elsif !e.inspect.match(/(it|name) already exists/)
|
598
|
-
raise MuError, "Problem managing entry for #{dns_name} -> #{target}: #{e.inspect}"
|
599
|
-
else
|
600
|
-
MU.log "#{dns_name} already exists", MU::DEBUG, details: e.inspect
|
601
|
-
end
|
602
|
-
end
|
606
|
+
MU::Cloud::AWS::DNSZone.manageRecord(mu_zone.id, dns_name, record_type, targets: [target], delete: delete, sync_wait: sync_wait, noop: noop)
|
603
607
|
return "#{dns_name}.platform-mu"
|
604
608
|
else
|
605
609
|
return nil
|
@@ -382,9 +382,8 @@ module MU
|
|
382
382
|
# @param region [String]: The cloud provider region
|
383
383
|
# @return [void]
|
384
384
|
def self.cleanup(noop: false, ignoremaster: false, region: MU.curRegion, credentials: nil, flags: {})
|
385
|
-
filters =
|
386
|
-
|
387
|
-
filters = [
|
385
|
+
filters = if flags and flags["vpc_id"]
|
386
|
+
[
|
388
387
|
{name: "vpc-id", values: [flags["vpc_id"]]}
|
389
388
|
]
|
390
389
|
else
|
@@ -394,6 +393,7 @@ module MU
|
|
394
393
|
if !ignoremaster
|
395
394
|
filters << {name: "tag:MU-MASTER-IP", values: [MU.mu_public_ip]}
|
396
395
|
end
|
396
|
+
filters
|
397
397
|
end
|
398
398
|
|
399
399
|
# Some services create sneaky rogue ENIs which then block removal of
|
@@ -408,136 +408,111 @@ module MU
|
|
408
408
|
MU.log "Revoking rules in EC2 Security Group #{sg.group_name} (#{sg.group_id})"
|
409
409
|
|
410
410
|
if !noop
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
ingress_to_revoke.each { |rule|
|
416
|
-
if !rule[:user_id_group_pairs].nil? and rule[:user_id_group_pairs] .size == 0
|
417
|
-
rule.delete(:user_id_group_pairs)
|
418
|
-
elsif !rule[:user_id_group_pairs].nil?
|
419
|
-
rule[:user_id_group_pairs].each { |group_ref|
|
420
|
-
group_ref = MU.structToHash(group_ref)
|
421
|
-
group_ref.delete(:group_name) if group_ref[:group_id]
|
422
|
-
}
|
423
|
-
end
|
411
|
+
revoke_rules(sg, region: region, credentials: credentials)
|
412
|
+
revoke_rules(sg, egress: true, region: region, credentials: credentials)
|
413
|
+
end
|
414
|
+
}
|
424
415
|
|
425
|
-
|
426
|
-
|
427
|
-
|
416
|
+
resp.data.security_groups.each { |sg|
|
417
|
+
next if sg.group_name == "default"
|
418
|
+
MU.log "Removing EC2 Security Group #{sg.group_name}"
|
428
419
|
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
420
|
+
on_retry = Proc.new {
|
421
|
+
# try to get out from under loose network interfaces with which
|
422
|
+
# we're associated
|
423
|
+
if sg.vpc_id
|
424
|
+
default_sg = MU::Cloud::AWS::VPC.getDefaultSg(sg.vpc_id, region: region, credentials: credentials)
|
425
|
+
if default_sg
|
426
|
+
eni_resp = MU::Cloud::AWS.ec2(credentials: credentials, region: region).describe_network_interfaces(
|
427
|
+
filters: [ {name: "group-id", values: [sg.group_id]} ]
|
428
|
+
)
|
429
|
+
if eni_resp and eni_resp.data and
|
430
|
+
eni_resp.data.network_interfaces
|
431
|
+
eni_resp.data.network_interfaces.each { |iface|
|
432
|
+
iface_groups = iface.groups.map { |if_sg| if_sg.group_id }
|
433
|
+
iface_groups.delete(sg.group_id)
|
434
|
+
iface_groups << default_sg if iface_groups.empty?
|
435
|
+
MU.log "Attempting to remove #{sg.group_id} (#{sg.group_name}) from ENI #{iface.network_interface_id}"
|
436
|
+
begin
|
437
|
+
MU::Cloud::AWS.ec2(credentials: credentials, region: region).modify_network_interface_attribute(
|
438
|
+
network_interface_id: iface.network_interface_id,
|
439
|
+
groups: iface_groups
|
440
|
+
)
|
441
|
+
rescue ::Aws::EC2::Errors::InvalidNetworkInterfaceIDNotFound
|
442
|
+
# fine by me
|
443
|
+
rescue ::Aws::EC2::Errors::AuthFailure
|
444
|
+
MU.log "Permission denied attempting to trim Security Group list for #{iface.network_interface_id}", MU::WARN, details: iface.groups.map { |g| g.group_name }.join(",")+" => default"
|
445
|
+
end
|
447
446
|
}
|
448
447
|
end
|
448
|
+
end
|
449
|
+
end
|
450
|
+
}
|
449
451
|
|
450
|
-
|
451
|
-
|
452
|
-
|
452
|
+
if !noop
|
453
|
+
MU.retrier([Aws::EC2::Errors::DependencyViolation, Aws::EC2::Errors::InvalidGroupInUse], ignoreme: [Aws::EC2::Errors::InvalidGroupNotFound], max: 10, wait: 10, on_retry: on_retry) {
|
454
|
+
begin
|
455
|
+
MU::Cloud::AWS.ec2(credentials: credentials, region: region).delete_security_group(group_id: sg.group_id)
|
456
|
+
rescue Aws::EC2::Errors::CannotDelete => e
|
457
|
+
MU.log e.message, MU::WARN
|
458
|
+
end
|
459
|
+
}
|
460
|
+
end
|
453
461
|
|
454
|
-
|
455
|
-
|
456
|
-
end
|
462
|
+
}
|
463
|
+
end
|
457
464
|
|
458
|
-
|
459
|
-
|
460
|
-
|
465
|
+
def self.revoke_rules(sg, egress: false, region: MU.myregion, credentials: nil)
|
466
|
+
holes = sg.send(egress ? :ip_permissions_egress : :ip_permissions)
|
467
|
+
|
468
|
+
to_revoke = []
|
469
|
+
|
470
|
+
holes.each { |hole|
|
471
|
+
to_revoke << MU.structToHash(hole)
|
472
|
+
to_revoke.each { |rule|
|
473
|
+
if !rule[:user_id_group_pairs].nil? and rule[:user_id_group_pairs].size == 0
|
474
|
+
rule.delete(:user_id_group_pairs)
|
475
|
+
elsif !rule[:user_id_group_pairs].nil?
|
476
|
+
rule[:user_id_group_pairs].each { |group_ref|
|
477
|
+
group_ref = MU.structToHash(group_ref)
|
478
|
+
group_ref.delete(:group_name) if group_ref[:group_id]
|
461
479
|
}
|
462
|
-
|
463
|
-
begin
|
480
|
+
end
|
464
481
|
|
465
|
-
|
466
|
-
|
467
|
-
group_id: sg.group_id,
|
468
|
-
ip_permissions: ingress_to_revoke
|
469
|
-
)
|
470
|
-
end
|
471
|
-
if egress_to_revoke.size > 0
|
472
|
-
MU::Cloud::AWS.ec2(credentials: credentials, region: region).revoke_security_group_egress(
|
473
|
-
group_id: sg.group_id,
|
474
|
-
ip_permissions: egress_to_revoke
|
475
|
-
)
|
476
|
-
end
|
477
|
-
rescue Aws::EC2::Errors::InvalidPermissionNotFound
|
478
|
-
MU.log "Rule in #{sg.group_id} disappeared before I could remove it", MU::WARN
|
482
|
+
if !rule[:ip_ranges].nil? and rule[:ip_ranges].size == 0
|
483
|
+
rule.delete(:ip_ranges)
|
479
484
|
end
|
480
|
-
end
|
481
|
-
}
|
482
485
|
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
+
if !rule[:prefix_list_ids].nil? and rule[:prefix_list_ids].size == 0
|
487
|
+
rule.delete(:prefix_list_ids)
|
488
|
+
end
|
486
489
|
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
rescue Aws::EC2::Errors::InvalidGroupNotFound
|
493
|
-
MU.log "EC2 Security Group #{sg.group_name} disappeared before I could delete it!", MU::WARN
|
494
|
-
rescue Aws::EC2::Errors::DependencyViolation, Aws::EC2::Errors::InvalidGroupInUse
|
495
|
-
if retries < 10
|
496
|
-
MU.log "EC2 Security Group #{sg.group_name} is still in use, waiting...", MU::NOTICE
|
497
|
-
# try to get out from under loose network interfaces with which
|
498
|
-
# we're associated
|
499
|
-
if sg.vpc_id
|
500
|
-
# get the default SG for this VPC
|
501
|
-
default_resp = MU::Cloud::AWS.ec2(region: region, credentials: credentials).describe_security_groups(
|
502
|
-
filters: [
|
503
|
-
{ name: "group-name", values: ["default"] },
|
504
|
-
{ name: "vpc-id", values: [sg.vpc_id] }
|
505
|
-
]
|
506
|
-
).security_groups
|
507
|
-
if default_resp and default_resp.size == 1
|
508
|
-
default_sg = default_resp.first.group_id
|
509
|
-
eni_resp = MU::Cloud::AWS.ec2(credentials: credentials, region: region).describe_network_interfaces(
|
510
|
-
filters: [ {name: "group-id", values: [sg.group_id]} ]
|
511
|
-
)
|
512
|
-
if eni_resp and eni_resp.data and
|
513
|
-
eni_resp.data.network_interfaces
|
514
|
-
eni_resp.data.network_interfaces.each { |iface|
|
515
|
-
iface_groups = iface.groups.map { |if_sg| if_sg.group_id }
|
516
|
-
iface_groups.delete(sg.group_id)
|
517
|
-
iface_groups << default_sg if iface_groups.empty?
|
518
|
-
MU.log "Attempting to remove #{sg.group_id} (#{sg.group_name}) from ENI #{iface.network_interface_id}"
|
519
|
-
begin
|
520
|
-
MU::Cloud::AWS.ec2(credentials: credentials, region: region).modify_network_interface_attribute(
|
521
|
-
network_interface_id: iface.network_interface_id,
|
522
|
-
groups: iface_groups
|
523
|
-
)
|
524
|
-
rescue ::Aws::EC2::Errors::AuthFailure
|
525
|
-
MU.log "Permission denied attempting to trim Security Group list for #{iface.network_interface_id}", MU::WARN, details: iface.groups.map { |g| g.group_name }.join(",")+" => default"
|
526
|
-
end
|
527
|
-
}
|
528
|
-
end
|
529
|
-
end
|
530
|
-
end
|
490
|
+
if !rule[:ipv_6_ranges].nil? and rule[:ipv_6_ranges].size == 0
|
491
|
+
rule.delete(:ipv_6_ranges)
|
492
|
+
end
|
493
|
+
}
|
494
|
+
}
|
531
495
|
|
532
|
-
|
533
|
-
|
534
|
-
|
496
|
+
if to_revoke.size > 0
|
497
|
+
begin
|
498
|
+
if egress
|
499
|
+
MU::Cloud::AWS.ec2(credentials: credentials, region: region).revoke_security_group_egress(
|
500
|
+
group_id: sg.group_id,
|
501
|
+
ip_permissions: to_revoke
|
502
|
+
)
|
535
503
|
else
|
536
|
-
MU.
|
504
|
+
MU::Cloud::AWS.ec2(credentials: credentials, region: region).revoke_security_group_ingress(
|
505
|
+
group_id: sg.group_id,
|
506
|
+
ip_permissions: to_revoke
|
507
|
+
)
|
537
508
|
end
|
509
|
+
rescue Aws::EC2::Errors::InvalidPermissionNotFound
|
510
|
+
MU.log "Rule in #{sg.group_id} disappeared before I could remove it", MU::WARN
|
538
511
|
end
|
539
|
-
|
512
|
+
end
|
513
|
+
|
540
514
|
end
|
515
|
+
private_class_method :revoke_rules
|
541
516
|
|
542
517
|
# Cloud-specific configuration properties.
|
543
518
|
# @param _config [MU::Config]: The calling MU::Config object
|
@@ -719,32 +694,7 @@ module MU
|
|
719
694
|
|
720
695
|
private
|
721
696
|
|
722
|
-
|
723
|
-
# Manufacture an EC2 security group. The second parameter, rules, is an
|
724
|
-
# "ingress_rules" structure parsed and validated by MU::Config.
|
725
|
-
#########################################################################
|
726
|
-
def setRules(rules, add_to_self: false, ingress: true, egress: false)
|
727
|
-
describe
|
728
|
-
# XXX warn about attempt to set rules before we exist
|
729
|
-
return if rules.nil? or rules.size == 0 or !@cloud_id
|
730
|
-
|
731
|
-
# add_to_self means that this security is a "member" of its own rules
|
732
|
-
# (which is to say, objects that have this SG are allowed in my these
|
733
|
-
# rules)
|
734
|
-
if add_to_self
|
735
|
-
rules.each { |rule|
|
736
|
-
if rule['sgs'].nil? or !rule['sgs'].include?(@cloud_id)
|
737
|
-
new_rule = rule.clone
|
738
|
-
new_rule.delete('hosts')
|
739
|
-
rule['sgs'] = Array.new if rule['sgs'].nil?
|
740
|
-
rule['sgs'] << @cloud_id
|
741
|
-
end
|
742
|
-
}
|
743
|
-
end
|
744
|
-
|
745
|
-
ec2_rules = convertToEc2(rules)
|
746
|
-
ext_permissions = MU.structToHash(cloud_desc.ip_permissions)
|
747
|
-
|
697
|
+
def purge_extraneous_rules(ec2_rules, ext_permissions)
|
748
698
|
# Purge any old rules that we're sure we created (check the comment)
|
749
699
|
# but which are no longer configured.
|
750
700
|
ext_permissions.each { |ext_rule|
|
@@ -781,97 +731,110 @@ module MU
|
|
781
731
|
ip_permissions: [ext_rule]
|
782
732
|
)
|
783
733
|
end
|
784
|
-
|
785
734
|
}
|
735
|
+
end
|
786
736
|
|
787
|
-
|
788
|
-
|
789
|
-
|
790
|
-
|
791
|
-
|
792
|
-
|
793
|
-
|
794
|
-
|
795
|
-
|
796
|
-
|
797
|
-
|
798
|
-
|
799
|
-
|
800
|
-
|
801
|
-
|
802
|
-
|
803
|
-
|
804
|
-
|
805
|
-
|
806
|
-
break
|
807
|
-
end
|
808
|
-
}
|
809
|
-
if haverule and !different
|
810
|
-
MU.log "Security Group rule already up-to-date in #{@mu_name}", MU::DEBUG, details: rule
|
811
|
-
next
|
737
|
+
#########################################################################
|
738
|
+
# Manufacture an EC2 security group. The second parameter, rules, is an
|
739
|
+
# "ingress_rules" structure parsed and validated by MU::Config.
|
740
|
+
#########################################################################
|
741
|
+
def setRules(rules, add_to_self: false, ingress: true, egress: false)
|
742
|
+
describe
|
743
|
+
# XXX warn about attempt to set rules before we exist
|
744
|
+
return if rules.nil? or rules.size == 0 or !@cloud_id
|
745
|
+
|
746
|
+
# add_to_self means that this security is a "member" of its own rules
|
747
|
+
# (which is to say, objects that have this SG are allowed in my these
|
748
|
+
# rules)
|
749
|
+
if add_to_self
|
750
|
+
rules.each { |rule|
|
751
|
+
if rule['sgs'].nil? or !rule['sgs'].include?(@cloud_id)
|
752
|
+
new_rule = rule.clone
|
753
|
+
new_rule.delete('hosts')
|
754
|
+
rule['sgs'] = Array.new if rule['sgs'].nil?
|
755
|
+
rule['sgs'] << @cloud_id
|
812
756
|
end
|
757
|
+
}
|
758
|
+
end
|
813
759
|
|
814
|
-
|
815
|
-
|
816
|
-
|
817
|
-
|
818
|
-
|
819
|
-
|
820
|
-
|
821
|
-
|
822
|
-
|
823
|
-
|
824
|
-
|
825
|
-
|
760
|
+
ec2_rules = convertToEc2(rules)
|
761
|
+
return if ec2_rules.nil?
|
762
|
+
|
763
|
+
ext_permissions = MU.structToHash(cloud_desc.ip_permissions)
|
764
|
+
|
765
|
+
purge_extraneous_rules(ec2_rules, ext_permissions)
|
766
|
+
|
767
|
+
ec2_rules.uniq!
|
768
|
+
ec2_rules.each { |rule|
|
769
|
+
haverule = nil
|
770
|
+
different = false
|
771
|
+
ext_permissions.each { |ext_rule|
|
772
|
+
if rule[:from_port] == ext_rule[:from_port] and
|
773
|
+
rule[:to_port] == ext_rule[:to_port] and
|
774
|
+
rule[:ip_protocol] == ext_rule[:ip_protocol]
|
775
|
+
haverule = ext_rule
|
776
|
+
ext_rule.keys.each { |k|
|
777
|
+
if ext_rule[k].nil? or ext_rule[k] == []
|
778
|
+
haverule.delete(k)
|
826
779
|
end
|
780
|
+
different = true if rule[k] != ext_rule[k]
|
781
|
+
}
|
782
|
+
break
|
783
|
+
end
|
784
|
+
}
|
785
|
+
if haverule and !different
|
786
|
+
MU.log "Security Group rule already up-to-date in #{@mu_name}", MU::DEBUG, details: rule
|
787
|
+
next
|
788
|
+
end
|
789
|
+
|
790
|
+
MU.log "Setting #{ingress ? "ingress" : "egress"} rule in Security Group #{@mu_name} (#{@cloud_id})", MU::NOTICE, details: rule
|
791
|
+
|
792
|
+
MU.retrier([Aws::EC2::Errors::InvalidGroupNotFound], max: 10, wait: 10, ignoreme: [Aws::EC2::Errors::InvalidPermissionDuplicate]) {
|
793
|
+
if ingress
|
794
|
+
if haverule
|
827
795
|
begin
|
828
|
-
MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).
|
796
|
+
MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).revoke_security_group_ingress(
|
829
797
|
group_id: @cloud_id,
|
830
|
-
ip_permissions: [
|
798
|
+
ip_permissions: [haverule]
|
831
799
|
)
|
832
|
-
rescue Aws::EC2::Errors::
|
833
|
-
MU.log "FirewallRule #{@mu_name} had a bogus rule: #{e.message}", MU::ERR, details: rule
|
834
|
-
raise e
|
800
|
+
rescue Aws::EC2::Errors::InvalidPermissionNotFound
|
835
801
|
end
|
836
802
|
end
|
837
|
-
|
838
|
-
|
839
|
-
if haverule
|
840
|
-
begin
|
841
|
-
MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).revoke_security_group_egress(
|
842
|
-
group_id: @cloud_id,
|
843
|
-
ip_permissions: [haverule]
|
844
|
-
)
|
845
|
-
rescue Aws::EC2::Errors::InvalidPermissionNotFound => e
|
846
|
-
end
|
847
|
-
end
|
848
|
-
MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).authorize_security_group_egress(
|
803
|
+
begin
|
804
|
+
MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).authorize_security_group_ingress(
|
849
805
|
group_id: @cloud_id,
|
850
806
|
ip_permissions: [rule]
|
851
807
|
)
|
808
|
+
rescue Aws::EC2::Errors::InvalidParameterCombination => e
|
809
|
+
MU.log "FirewallRule #{@mu_name} had a bogus rule: #{e.message}", MU::ERR, details: rule
|
810
|
+
raise e
|
852
811
|
end
|
812
|
+
end
|
853
813
|
|
854
|
-
|
855
|
-
|
856
|
-
|
857
|
-
|
858
|
-
|
859
|
-
|
860
|
-
|
861
|
-
|
814
|
+
if egress
|
815
|
+
if haverule
|
816
|
+
begin
|
817
|
+
MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).revoke_security_group_egress(
|
818
|
+
group_id: @cloud_id,
|
819
|
+
ip_permissions: [haverule]
|
820
|
+
)
|
821
|
+
rescue Aws::EC2::Errors::InvalidPermissionNotFound
|
822
|
+
end
|
862
823
|
end
|
863
|
-
|
864
|
-
|
824
|
+
MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).authorize_security_group_egress(
|
825
|
+
group_id: @cloud_id,
|
826
|
+
ip_permissions: [rule]
|
827
|
+
)
|
865
828
|
end
|
866
829
|
}
|
867
|
-
|
830
|
+
}
|
868
831
|
|
869
832
|
end
|
870
833
|
|
871
|
-
|
872
|
-
# Convert our config languages description of firewall rules into
|
873
|
-
#
|
874
|
-
|
834
|
+
#######################################################################
|
835
|
+
# Convert our config languages description of firewall rules into
|
836
|
+
# Amazon's. Our rule structure is as defined in MU::Config.
|
837
|
+
#######################################################################
|
875
838
|
def convertToEc2(rules)
|
876
839
|
ec2_rules = []
|
877
840
|
if rules != nil
|
@@ -995,8 +958,8 @@ module MU
|
|
995
958
|
ec2_rules << ec2_rule
|
996
959
|
}
|
997
960
|
end
|
998
|
-
|
999
|
-
|
961
|
+
|
962
|
+
ec2_rules.uniq
|
1000
963
|
end
|
1001
964
|
|
1002
965
|
end #class
|