cloud-mu 3.1.4 → 3.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|