AWS::Networks - Parser und Filter für AWS IP-Adressbereiche

Veröffentlicht von Thomas Fahle am (Permalink)

Amazon Web Services (AWS) veröffentlicht seine aktuellen IP-Adressbereiche regelmäßig im JSON-Format.

AWS::Networks von Jose Luis Martinez Torres stellt einen Parser und verschiedene Filter für AWS Netzwerkbereiche bereit.

Diese so ermittelten Netzwerkbereiche können dann mit bereits existierenden CPAN Modulen für IP-Adressbereiche, wie Net::CIDR::Set, weiter verarbeitet werden.

AWS::Networks in Version 0.01, das für diesen Beitrag verwendet wird, kann leider nur IPv4 Adressbereiche aus den von AWS bereitgestellten Daten parsen bzw. filtern.

 

Basics

Das nachfolgende Beispiel lädt die ip-ranges.json Datei von AWS herunter, zeigt den Zeitpunkt der Veröffentlichung an und listet alle AWS IP-Adressbereiche im CIDR-Format auf.

#!/usr/bin/perl 
use strict;
use warnings;

use AWS::Networks;

my $nets = AWS::Networks->new();

print $nets->sync_token->iso8601, "\n";

foreach my $cidr ( @{ $nets->cidrs } ) {
    print "$cidr\n";
}

Das Programm erzeugt folgende (gekürzte) Ausgabe:

2017-06-22T22:12:11
13.32.0.0/15
13.52.0.0/15
13.54.0.0/15
13.56.0.0/16
13.57.0.0/16
13.58.0.0/15
.....
54.240.128.0/18
204.246.164.0/22
204.246.168.0/22
204.246.174.0/23
204.246.176.0/20
205.251.192.0/19
205.251.249.0/24
205.251.250.0/23
205.251.252.0/23
205.251.254.0/24
216.137.32.0/19

Wer bereits eine ip-ranges.json Datei lokal vorliegen hat, kann diese wie folgt mit File::Slurp einlesen:

#!/usr/bin/perl 
use strict;
use warnings;

use File::Slurp;
use JSON;
use AWS::Networks;

# https://ip-ranges.amazonaws.com/ip-ranges.json
my $ip_ranges_json_file = 'ip-ranges.json';

my $json = read_file($ip_ranges_json_file);
my $nets = AWS::Networks->new( netinfo => decode_json($json) );

print $nets->sync_token->iso8601, "\n";

foreach my $cidr ( @{ $nets->cidrs } ) {
    print "$cidr\n";
}

Ausgabe des Programms wie oben.

Hinweis: Das Modul AWS::IP, das eine ähnliche Funktionalität anbietet, verwendet einen Cache für die ip-ranges.json Datei.

 

Ist diese IP eine AWS IP Adresse?

Das nachfolgende Kommandozeilentool prüft, ob eine IPv4 Adresse in den AWS IP-Adressbereichen enthalten ist:

#!/usr/bin/perl 
use strict;
use warnings;

use feature 'say';

use AWS::Networks;
use Net::CIDR::Set;

my $ip = $ARGV[0];

unless ($ip) {
    die "Usage: $0 IPv4-address\n";
}

my $nets = AWS::Networks->new();

my $cidrs = $nets->cidrs;

my $cidr_set = Net::CIDR::Set->new(@$cidrs);

if ( $cidr_set->contains($ip) ) {
    say "Yes - $ip is a AWS IP.";
} else {
    say "No - $ip is not a AWS IP.";
}

Das Programm erzeugt folgende Ausgabe:

$ perl ip.pl 216.137.32.6
Yes - 216.137.32.6 is a AWS IP.

$ perl ip.pl 127.0.0.1
No - 127.0.0.1 is not a AWS IP.

Jose Luis Martinez Torres liefert mit der Distribution auch das umfangreichere Tool aws_ip aus.

 

Nach Services filtern

Die Methode services() liefert eine Liste aller verfügbaren Services:

#!/usr/bin/perl 
use strict;
use warnings;
use feature 'say';

use AWS::Networks;

my $nets = AWS::Networks->new();

foreach my $service ( @{ $nets->services } ) {
    say "$service";
}

Das Programm erzeugt folgende Ausgabe:

EC2
CLOUDFRONT
ROUTE53_HEALTHCHECKS
ROUTE53
S3
AMAZON

Die Methode by_service( ) liefert eine Liste aller Netzwerkbereiche für einen bestimmten Service

Eine Übersicht über alle Netzwerkbereiche für alle Services erhält man wie folgt:

#!/usr/bin/perl 
use strict;
use warnings;
use feature 'say';

use AWS::Networks;

my $nets = AWS::Networks->new();

foreach my $service ( @{ $nets->services } ) {
    say "$service";
    my $aws_networks_object = $nets->by_service($service);
    foreach my $cidr ( @{ $aws_networks_object->cidrs } ) {
        say "\t$cidr";
    }
}

Das Programm erzeugt folgende (gekürzte) Ausgabe:

ROUTE53
        52.95.110.0/24
        205.251.192.0/21
ROUTE53_HEALTHCHECKS
        54.183.255.128/26
        54.228.16.0/26
....
AMAZON
        13.32.0.0/15
        13.52.0.0/15
        13.54.0.0/15
....
CLOUDFRONT
        13.32.0.0/15
        13.54.63.128/26
....
S3
        52.82.188.0/22
        52.92.0.0/20
....
EC2
        13.52.0.0/15
        13.54.0.0/15
        13.56.0.0/16
....

 

Nach Regionen filtern

Die Methode regions() liefert eine Liste aller verfügbaren AWS Regionen und die Methode by_region() liefert eine Liste aller Netzwerkbereiche für eine bestimmte Region.

Eine Übersicht über alle Netzwerkbereiche für alle Regionen erhält man wie folgt:

#!/usr/bin/perl 
use strict;
use warnings;
use feature 'say';

use AWS::Networks;

my $nets = AWS::Networks->new();

foreach my $region ( @{ $nets->regions } ) {
    say "$region";
    my $aws_networks_object = $nets->by_region($region);
    foreach my $cidr ( @{ $aws_networks_object->cidrs } ) {
        say "\t$cidr";
    }
}

Das Programm erzeugt folgende (gekürzte) Ausgabe:

cn-north-1
        52.80.0.0/16
        52.94.249.0/28
        52.95.255.144/28
        54.222.0.0/19
....
sa-east-1
        18.231.0.0/16
        52.67.0.0/16
        52.92.39.0/24
....
eu-west-1
	34.240.0.0/13
	34.248.0.0/13
	46.51.128.0/18
....

 

Nach Regionen und Services filtern

Manchmal möchte man die IP-Adressbereiche für einen bestimmten Service in einer bestimmten Region ermitteln.

Hierzu ermittelt man zunächst alle IP-Adressbereiche für den gewünschten Service und alle IP-Adressbereiche für die gewünschte Region.

Diese beiden Sets (Mengen) werden mit und zu einer neuen Menge verknüpft.

#!/usr/bin/perl 
use strict;
use warnings;

use feature 'say';

use AWS::Networks;
use Net::CIDR::Set;

my $region_set  = cidr_set_for_region('eu-west-1');
my $service_set = cidr_set_for_service('EC2');

my $overlap = $region_set->intersection($service_set);

my $iter = $overlap->iterate_cidr;
while ( my $cidr = $iter->() ) {
    say $cidr;
}
exit();

# Returns a Net::CIDR::Set object filled with AWS CIDRs for $service
sub cidr_set_for_service {
    my $service  = shift;
    my $nets     = AWS::Networks->new();
    my $s        = $nets->by_service($service);
    my $cidrs    = $s->cidrs;
    my $cidr_set = Net::CIDR::Set->new(@$cidrs);
    return $cidr_set;
}
# Returns a Net::CIDR::Set object filled with AWS CIDRs for $region
sub cidr_set_for_region {
    my $region   = shift;
    my $nets     = AWS::Networks->new();
    my $r        = $nets->by_region($region);
    my $cidrs    = $r->cidrs;
    my $cidr_set = Net::CIDR::Set->new(@$cidrs);
    return $cidr_set;
}

Das Programm erzeugt folgende Ausgabe:

34.240.0.0/12
46.51.128.0/18
46.51.192.0/20
46.137.0.0/17
46.137.128.0/18
52.16.0.0/14
52.30.0.0/15
52.48.0.0/14
52.95.244.0/24
52.95.255.64/28
52.208.0.0/13
54.72.0.0/14
54.76.0.0/15
54.78.0.0/16
54.154.0.0/15
54.170.0.0/15
54.194.0.0/15
54.216.0.0/15
54.220.0.0/16
54.228.0.0/15
54.246.0.0/15
79.125.0.0/17
176.34.64.0/18
176.34.128.0/17
185.48.120.0/22

 

IP-Ranges zur Kontrolle ausgehenden Datenverkehrs (egress control)

In der offiziellen AWS Dokumentation wird folgendes Beispiel Implementieren der Kontrolle ausgehenden Datenverkehrs aufgeführt, das als Ausgangspunkt für das nachfolgende Programm dient.

"Um einer Instance nur den Zugriff auf AWS-Services zu erlauben, erstellen Sie eine Sicherheitsgruppe mit Regeln, die ausgehenden Datenverkehr zu den CIDR-Blöcken in der AMAZON-Liste zulassen, abzüglich der CIDR-Blöcke, die auch in der EC2-Liste enthalten sind."

Hierzu ermittelt man zunächst alle IP-Adressbereiche für die gewünschten Services (AMAZON und EC2).

Anschließend wird die Menge der EC2-Bereiche von der Menge der AMAZON-Bereiche abgezogen.

#!/usr/bin/perl 
use strict;
use warnings;

use feature 'say';

use AWS::Networks;
use Net::CIDR::Set;

# http://docs.aws.amazon.com/general/latest/gr/aws-ip-ranges.html

# Implementing Egress Control

# To allow an instance to access only AWS services, create a security group
# with rules that allow outbound traffic to the CIDR blocks in the AMAZON list,
# minus the CIDR blocks that are also in the EC2 list.

my $amazon_set = cidr_set_for_service('AMAZON');
my $ec2_set    = cidr_set_for_service('EC2');

my $egress_set = $amazon_set->diff($ec2_set);

my $iter = $egress_set->iterate_cidr;
while ( my $cidr = $iter->() ) {
    say $cidr;
}
exit();

# Returns a Net::CIDR::Set object filled with
# AWS CIDRs for $service
sub cidr_set_for_service {
    my $service  = shift;
    my $nets     = AWS::Networks->new();
    my $s        = $nets->by_service($service);
    my $cidrs    = $s->cidrs;
    my $cidr_set = Net::CIDR::Set->new(@$cidrs);
    return $cidr_set;
}

Das Programm erzeugt folgende (gekürzte) Ausgabe:

13.32.0.0/15
27.0.0.0/22
43.250.192.0/23
52.46.0.0/18
52.46.64.0/19
52.82.187.0/24
52.82.188.0/22
52.82.196.0/22
52.82.200.0/21
52.82.208.0/20
....
204.246.174.0/23
204.246.176.0/20
205.251.192.0/19
205.251.224.0/20
205.251.240.0/22
205.251.244.0/23
205.251.247.0/24
205.251.248.0/22
205.251.252.0/23
205.251.254.0/24
207.171.160.0/19
216.137.32.0/19

 

Siehe auch

 

Weitere Posts