artykuły

VPC – prywatne podsieci

Brak komentarzy

W poprzednim artykule dowiedzieliśmy się jak zbudowana jest sieć domyślnie dostarczana dla każdego nowego konta (default VPC) . Składa się ona z trzech publicznych podsieci, pozwalając na umieszczanie w niej zasobów wspierających publiczne adresowanie. Wyklucza to użycie choćby lambd, ponieważ nie jest możliwe przypisanie im publicznego adresu IP. Takie podejście nie wspiera również ograniczenia dostępu do zasobów, które nie muszą lub wręcz nie powinny być adresowane z publicznego Internetu.

Przyjrzymy się dwóm przypadkom. Pierwszym z nich będzie wystawienie API, drugim aplikacja do raportowania do naszego partnera biznesowego.

Przypadek pierwszy – API

Opis

Mamy aplikacje będącą backendem dla klientów mobilnych oraz przeglądarek. Jedną częścią aplikacji jest API, które jest publicznie dostępne. Drugą częścią jest baza danych dla której krytycznym wymaganiem jest by nie była dostępna przez Internet.

Rozwiązanie

Jednym ze sposobów na rozwiązanie tego problemu jest utworzenie dodatkowego, prywatnego subnetu w którym umieścimy naszą bazę danych. Takie rozwiązanie widoczne jest na poniższym diagramie.

Rozwiązanie pierwsze, struktura VPC, publiczna i prywatna podsieć

Widzimy tutaj EC2 na którym umieścimy nasze API znajdujące się w publicznym subnecie. Security grupa przypisana do niego zezwala na ruch przychodzący z dowolnego miejsca. Cenna baza danych siedzi w prywatnym subnecie. Jest opakowana osobną security grupą, która pozwala tylko na ruch na jednym porcie pochodzący z grupy naszego API.

Prywatny subnet

Prywatny subnet różni się od publicznego tym, że nie posiada bezpośredniego połączenia sieciowego do Internet Gateway’a. Na przytoczonym przykładzie widać to dokładnie na powiązanej z nim tablicy routingu – gdzie trasujemy tylko pakiety wewnątrz naszego VPC (10.0.0.0/16).

Implementacja

Najpierw tworzymy vpc, internet gateway oraz wiążemy je ze sobą:

    Vpc:
        Type: AWS::EC2::VPC
        Properties:
            CidrBlock: 10.0.0.0/16
            EnableDnsHostnames: true
    InternetGateway:
        Type: AWS::EC2::InternetGateway
    InternetGatewayAttachment:
        Type: AWS::EC2::VPCGatewayAttachment
        Properties:
            InternetGatewayId: !Ref InternetGateway
            VpcId: !Ref Vpc

Następnie tworzymy tablicę routingu oraz określamy w niej trasę do internet gatewaya, efektywnie sprawiając, że każdy subnet do którego przypiszemy tą tablicę będzie publiczny.

    PublicRouteTable:
        Type: AWS::EC2::RouteTable
        Properties:
            VpcId: !Ref Vpc
    InternetRoute:
        Type: AWS::EC2::Route
        Properties:
            DestinationCidrBlock: 0.0.0.0/0
            RouteTableId: !Ref PublicRouteTable
            GatewayId: !Ref InternetGateway

Tworzymy drugą tablicę routingu, która potrafi trasować pakiety tylko wewnątrz naszego VPC.

    PrivateSubnet:
        Type: AWS::EC2::Subnet
        Properties:
            AvailabilityZone: eu-west-1c
            CidrBlock: 10.0.3.0/24
            MapPublicIpOnLaunch: true
            VpcId: !Ref Vpc

Tworzymy subnet publiczny oraz prywatny i wiążemy je ze stworzonymi tablicami.

    PublicSubnet:
        Type: AWS::EC2::Subnet
        Properties:
            AvailabilityZone: eu-west-1a
            CidrBlock: 10.0.1.0/24
            MapPublicIpOnLaunch: true
            VpcId: !Ref Vpc
    PublicSubnetTableAssociation:
        Type: AWS::EC2::SubnetRouteTableAssociation
        Properties:
            RouteTableId: !Ref PublicRouteTable
            SubnetId: !Ref PublicSubnet
    PublicRouteTable:
        Type: AWS::EC2::RouteTable
        Properties:
            VpcId: !Ref Vpc

    PrivateSubnet:
        Type: AWS::EC2::Subnet
        Properties:
            AvailabilityZone: eu-west-1c
            CidrBlock: 10.0.3.0/24
            VpcId: !Ref Vpc
    PrivateSubnetTableAssociation:
        Type: AWS::EC2::SubnetRouteTableAssociation
        Properties:
            RouteTableId: !Ref PrivateRouteTable
            SubnetId: !Ref PrivateSubnet

Pozostało nam jeszcze stworzyć security grupy dla API oraz RDSa. Zgodnie z wcześniejszym opisem grupa dla API zezwala na ruch z dowolnego adresu na porcie 443. Grupa dla bazy pozwala tylko na ruch po porcie 3306 (MySql) i tylko pochodzący od zasobów powiązanych z security grupą API.

    ApiSecurityGroup:
        Type: AWS::EC2::SecurityGroup
        Properties:
            GroupDescription: Api security group
            GroupName: api-security-group
            SecurityGroupIngress:
                -   Description: Open https traffic
                    CidrIp: 0.0.0.0/0
                    IpProtocol: TCP
                    FromPort: 443
                    ToPort: 443
            VpcId: !Ref Vpc
    DatabaseSecurityGroup:
        Type: AWS::EC2::SecurityGroup
        Properties:
            GroupDescription: Database secruity group
            GroupName: db-security-group
            SecurityGroupIngress:
                - Description: Allow traffic from the api                    
                  IpProtocol: TCP
                  FromPort: 3306
                  ToPort: 3306
                  SourceSecurityGroupId: !Ref ApiSecurityGroup
            VpcId: !Ref Vpc

Tak przygotowana sieć pozwala na umieszczenie w niej naszego API oraz RDSa.

Cały template gotowy na dodanie do niego EC2 i bazy dostępny jest tutaj.

Koszt

Dodanie drugiego subnetu oraz security grupy nie wpływa na zwiększenie kosztów. Mimo wszystko trzeba być świadomym tego ile kosztują EC2 oraz RDS które wykorzystujemy.

Przypadek drugi – raportowanie

Opis

Nasza aplikacja ma za zadanie wykonywać raportowanie do partnera biznesowego. By móc wysłać raport potrzebujemy połączyć się do bazy, wykonać jakieś operacje na danych i zarejestrować raport w określonym API, ot wszystko. Wymagamy by baza danych oraz nasza aplikacja nie były publicznie dostępne. Jednocześnie aplikacja musi być w stanie skontaktować się z API naszego partnera dostępnym po publicznym Internecie. Nasz partner oczekuje od nas podania zakresu IP z których będziemy się do niego łączyli.

Rozwiązanie

Struktura VPC, publiczna i prywatna podsieć. NAT Gateway.

Ponownie chcemy schować naszą bazę danych w prywatnym subnecie, tutaj nie powinno być wątpliwości.
Aby spełnić wymagania dotyczące aplikacji trzeba umieścić ją w prywatnym, ale lekko zmodyfikowanym subnecie. Konkretnie, ruch do adresów z poza naszego VPC (10.0.0.0/16) przekierować na NAT Gateway. Zajmie się on translacją adresu z prywatnego na publiczny. Wykorzystanie NAT Gateway’a w trasowaniu ruchu da nam dodatkowy plus w postaci stałego adresu IP z którego wychodzi na nasz ruch. Używany jest wtedy adresu IP gatewaya.

Elastic IP

Zasób Elastic IP to jeden publiczny adres IPv4. Taki adres możemy przypisać do innego zasobu, np EC2, NAT Gatewaya, itd. Samo pozyskanie adresu nic nie kosztuje, ale tylko jeżeli jest on powiązany z innym zasobem. W innym przypadku zostaje za niego naliczona opłata. Drugi i każdy kolejny adres przypisany do tego samego zasobu również obciąży nasz rachunek. W obu przypadkach AWS policzy $0,005 za każdą godzinę istnienia adresu.

Implementacja

Przy opisie tego rozwiązania pominiemy tworzenie VPC oraz publicznej podsieci ponieważ poruszyliśmy je chwilę temu.
Publiczny subnet musimy jednak rozszerzyć o NAT Gateway, robimy to dodając następujące zasoby do naszego CloudFormation.

    ElasticIpForNat:
        Type: AWS::EC2::EIP
        Properties:
            Domain: vpc
    NatGateway:
        Type: AWS::EC2::NatGateway
        Properties:
            AllocationId: !GetAtt ElasticIpForNat.AllocationId
            SubnetId: !Ref PublicSubnet

NAT wymaga tego by przypisany był do niego publiczny adres IP.

Zgodnie z opisem potrzebujemy stworzyć prywatny subnet dla aplikacji.

    ApplicationSubnet:
        Type: AWS::EC2::Subnet
        Properties:
            AvailabilityZone: eu-west-1a
            CidrBlock: 10.0.3.0/24
            VpcId: !Ref Vpc
    ApplicationSubnetRouteTable:
        Type: AWS::EC2::RouteTable
        Properties:
            VpcId: !Ref Vpc
    ApplicationSubnetTableAssociation:
        Type: AWS::EC2::SubnetRouteTableAssociation
        Properties:
            RouteTableId: !Ref ApplicationSubnetRouteTable
            SubnetId: !Ref ApplicationSubnet

W przypisanej do niego tablicy routingu musimy umieścić regułę, która ruch nie pasujący do naszego VPC skieruje na NAT Gateway.

    InternetRoute:
        Type: AWS::EC2::Route
        Properties:
            DestinationCidrBlock: 0.0.0.0/0
            RouteTableId: !Ref ApplicationSubnetRouteTable
            NatGatewayId: !Ref NatGateway    

Subnet dla bazy danych nie różni się od podanego w poprzednim przykładzie i wygląda następująco:

    DatabaseSubnet:
        Type: AWS::EC2::Subnet
        Properties:
            AvailabilityZone: eu-west-1a
            CidrBlock: 10.0.4.0/24
            VpcId: !Ref Vpc
    DatabaseRouteTable:
        Type: AWS::EC2::RouteTable
        Properties:
            VpcId: !Ref Vpc
    DatabaseSubnetTableAssociation:
        Type: AWS::EC2::SubnetRouteTableAssociation
        Properties:
            RouteTableId: !Ref DatabaseRouteTable
            SubnetId: !Ref DatabaseSubnet

Gotowy template dostępny jest tutaj.

Koszt

NAT Gateway wprowadza dodatkowy koszt. W przypadku rejonu eu-west-1 (Irlandia) jest to $0,048 za każdą godzinę działania oraz $0,048 za każdy przetworzony GB. Jeśli rozpatrzymy to w skali miesiąca to mamy 35,715 dolara za samo tylko istnienie gateway’a, nie uwzględniając transferu. Poza tym na poziomie sieciowym nie generujemy dodatkowych kosztów.

Tags: , , , , , ,

Powiązane artykuły

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *

Wypełnij to pole
Wypełnij to pole
Proszę wprowadzić prawidłowy adres email.
You need to agree with the terms to proceed

Menu