Application Load BalancerのCLI設定取得

Application Load Balancer(以下、ALB)の設定値をAWS CLIコマンドで取得するのに実行するコマンドが多すぎると思ったことはありますか?

ALBの設定パラメーターをCLIで取得するにあたり、ロードバランサーの設定・ターゲットグループの設定・リスナーの設定・リスナールールの設定など、確認したいポイント複数に対してそれぞれのdescribeコマンドを実行する必要があります。

そこで、よく確認する項目だけでも一覧化してALBのデータ確認を効率をするためのpythonコードになります。
また、ターゲット先のEC2やACM(HTTPS証明書)がインスタンスIDやACM ARNで出力されるため、EC2名や証明書名と比べて直感的にわかりにくい箇所をEC2名などの一目見てわかるように変換して出力してくれます。
具体的には以下の項目を一覧化して表示します。

  • ALB 設定
    — ALB名
    — 接続タイプ(内部向け or 外部向け)
    — IPアドレスタイプ
    — サブネット
    — セキュリティグループ
    — 属性設定
  • リスナー設定
    — 接続プロトコル
    — 接続ポート
    — (使用するデフォルト証明書)(HTTPSのみ)
    — 一部のリスナールール
  • ターゲットグループ設定
    — ターゲットグループ名
    — ターゲットタイプ
    — プロトコル
    — 接続ポート
    — ヘルスチェック設定
    — 属性設定

自分向けに作成しているため「この情報を追加出力したい」などあればアレンジして活用いただければと思います。

前提条件

  • Python : ver3.11.4 (細かなバージョン指定はありませんがPythonが実行できる環境が必要)
  • boto3 Library : インストール済み
  • AWS環境へのReadOnly権限 : データ参照する際に必要になる権限。(名前表示のための EC2をNameタグ/SG Name/ACM 証明書名などELB以外のリソースに対するreadonly権限も必要)
  • デフォルトリージョンを指定 : 特定のリージョンを事前指定済みであること

pythonコード

output_alb_status.py などの名前で下記コードを保存。

import sys
import datetime
import boto3
from distutils.util import strtobool


def main():
    if len(sys.argv) < 2:
        print('invalid argument.'
              '(example : python3 output_alb_status.py ALBName)')
        sys.exit(1)
    alb_name = sys.argv[1]

    client = boto3.client('elbv2')

    # get alb general status
    response = client.describe_load_balancers(
        Names=[
            alb_name
        ]
    )

    print_alb_parameter(response)
    print('\n')

    print_tg_parameter(response)


def print_alb_parameter(alb_para: dict):
    client = boto3.client('elbv2')

    response = alb_para['LoadBalancers'][0]
    attribute = client.describe_load_balancer_attributes(
        LoadBalancerArn=response['LoadBalancerArn']
    )

    print("###### ALB Parameter ##### ")
    print(f'  LoadBalancerName : {response["LoadBalancerName"]}')
    print(f'  Scheme           : {response["Scheme"]}')
    print(f'  IpAddressType    : {response["IpAddressType"]}')
    print('  Subnet1           ')
    print(f'    SubnetID       : {response["AvailabilityZones"][0]["SubnetId"]}')
    print(f'    AZ_Name        : {response["AvailabilityZones"][0]["ZoneName"]}')
    print('  Subnet2           ')
    print(f'    SubnetID       : {response["AvailabilityZones"][1]["SubnetId"]}')
    print(f'    AZ_Name        : {response["AvailabilityZones"][1]["ZoneName"]}')
    print('  SecurityGroup     ')
    for i, SecurityGroups in enumerate(response['SecurityGroups']):
        sg_name = return_sg_name(SecurityGroups)
        print(f'    SG{i}            : {sg_name}')

    print()
    print('  Attribute   ')
    for Attributes in attribute["Attributes"]:
        if 'deletion_protection.enabled' in Attributes.values():
            print(f'    DeletProtection: {Attributes["Value"]}')
    for Attributes in attribute["Attributes"]:
        if 'idle_timeout.timeout_seconds' in Attributes.values():
            print(f'    IdleTimeOut    : {Attributes["Value"]}')
    for Attributes in attribute["Attributes"]:
        if 'routing.http2.enabled' in Attributes.values():
            print(f'    HTTP2Enable    : {Attributes["Value"]}')

    print()
    print('  AccessLog   ')
    for Attributes in attribute["Attributes"]:
        if 'access_logs.s3.enabled' in Attributes.values():
            print(f'    LogEnable     : {Attributes["Value"]}')
    for Attributes in attribute["Attributes"]:
        if 'access_logs.s3.bucket' in Attributes.values():
            print(f'    Backet        : {Attributes["Value"]}')
    for Attributes in attribute["Attributes"]:
        if 'access_logs.s3.prefix' in Attributes.values():
            print(f'    Prefix        : {Attributes["Value"]}')

    print()
    print('  Listener   ')
    print_listener_parameter(response['LoadBalancerArn'])


def print_listener_parameter(lb_arn):
    client = boto3.client('elbv2')
    listener = client.describe_listeners(
        LoadBalancerArn=lb_arn
    )

    for i, Listeners in enumerate(listener['Listeners']):
        print(f'    Listener{i}    ')
        print(f'      Protocol    : {Listeners["Protocol"]}')
        print(f'      Port        : {Listeners["Port"]}')
        if 'Certificates' in Listeners:
            for Certificates in Listeners['Certificates']:
                cert_name = return_acm_name(Certificates["CertificateArn"])
                print(f'      Cert{i}       : {cert_name}')
        else:
            print('      Cert        : None')

        if 'SslPolicy' in Listeners:
            print(f'      SslPolicy   : {Listeners["SslPolicy"]}')

        print_listener_rule(Listeners["ListenerArn"], i)
        print()


def print_listener_rule(listener_arn, i):
    client = boto3.client('elbv2')
    rules = client.describe_rules(
        ListenerArn=listener_arn
    )
    print()

    for j, Rule in enumerate(rules['Rules']):
        print(f'    ListerRule {i}-{j}')
        print(f'      Priority     : {Rule["Priority"]}')

        print('      Conditions   ')
        for Condition in Rule["Conditions"]:
            if 'source-ip' in Condition.values():
                print(f'        source-ip  : {Condition["SourceIpConfig"]}')
            elif 'host-header' in Condition.values():
                print(f'        host-header: {Condition["Values"]}')
            elif 'path-pattern' in Condition.values():
                print(f'        path-patter: {Condition["Values"]}')
            elif 'http-header' in Condition.values():
                print(f'        http-header: {Condition["HttpHeaderConfig"]}')
            else:
                print('        Condition Setting: None')

        print('      Actions   ')
        for Actions in Rule["Actions"]:
            if 'forward' in Actions.values():
                for k, targetgroup in enumerate(Actions['ForwardConfig']['TargetGroups']):
                    tg_response = client.describe_target_groups(
                        TargetGroupArns=[
                            targetgroup['TargetGroupArn']
                        ]
                    )
                    print(f'       forward    : {tg_response["TargetGroups"][0]["TargetGroupName"]}')
                    print(f'       Weight     : {targetgroup["Weight"]}')
                    print(f'       Stikiness  : {Actions["ForwardConfig"]["TargetGroupStickinessConfig"]["Enabled"]}')
            elif 'redirect' in Actions.values():
                print(f'        Redirect   : {Actions["RedirectConfig"]}')
            elif 'fixed-response' in Actions.values():
                print(f'        FixResponse: {Actions["FixedResponseConfig"]}')

            print()


def print_tg_parameter(alb_para):
    client = boto3.client('elbv2')

    lb_arn = alb_para['LoadBalancers'][0]['LoadBalancerArn']
    tg_para = client.describe_target_groups(
        LoadBalancerArn=lb_arn
    )

    for i, TargetGroups in enumerate(tg_para["TargetGroups"]):
        print(f"###### TG Parameter {i} ##### ")
        print(f'  TargetGroupName  : {TargetGroups["TargetGroupName"]}')
        print(f'  TargetType       : {TargetGroups["TargetType"]}')
        print(f'  Protocol         : {TargetGroups["Protocol"]}')
        print(f'  Port             : {TargetGroups["Port"]}')

        print()
        print('  HealthCheck      ')
        print(f'    Protocol       : {TargetGroups["HealthCheckProtocol"]}')
        print(f'    Path           : {TargetGroups["HealthCheckPath"]}')
        print(f'    Port           : {TargetGroups["HealthCheckPort"]}')
        print(f'    Threshold      : {TargetGroups["HealthyThresholdCount"]}')
        print(f'    UnHhealtyTH    : {TargetGroups["UnhealthyThresholdCount"]}')
        print(f'    Timeout        : {TargetGroups["HealthCheckTimeoutSeconds"]}')
        print(f'    Interval       : {TargetGroups["HealthCheckIntervalSeconds"]}')
        print(f'    SuccessCode    : {TargetGroups["Matcher"]["HttpCode"]}')

        print()
        print('  HealthCheckTarget      ')
        tg_instance = client.describe_target_health(
            TargetGroupArn=TargetGroups["TargetGroupArn"]
        )
        for i, HealthDescriptions in enumerate(tg_instance["TargetHealthDescriptions"]):
            instance_name = return_instance_name(HealthDescriptions["Target"]["Id"])
            print(f'    Target {i}       : {instance_name}')
            print(f'    Target {i} Health: {HealthDescriptions["TargetHealth"]["State"]}')

        print()
        print('  Attribute      ')
        tg_attribute = client.describe_target_group_attributes(
            TargetGroupArn=TargetGroups["TargetGroupArn"]
        )
        for tg_Attributes in tg_attribute["Attributes"]:
            if 'deregistration_delay.timeout_seconds' in tg_Attributes.values():
                print(f'    DerectionDelay : {tg_Attributes["Value"]}')
        for tg_Attributes in tg_attribute["Attributes"]:
            if 'slow_start.duration_seconds' in tg_Attributes.values():
                print(f'    SlowStart      : {tg_Attributes["Value"]}')
        for tg_Attributes in tg_attribute["Attributes"]:
            if 'load_balancing.algorithm.type' in tg_Attributes.values():
                print(f'    LbAlgorithm    : {tg_Attributes["Value"]}')
        for tg_Attributes in tg_attribute["Attributes"]:
            if 'stickiness.enabled' in tg_Attributes.values():
                print(f'    Stickiness     : {tg_Attributes["Value"]}')

                if strtobool(tg_Attributes["Value"]):
                    for stickinessAttri in tg_attribute["Attributes"]:
                        if 'stickiness.type' in stickinessAttri.values():
                            print(f'    StickinessType : {stickinessAttri["Value"]}')
                            if stickinessAttri["Value"] == "lb_cookie":
                                for stickinessAttri in tg_attribute["Attributes"]:
                                    if 'stickiness.lb_cookie.duration_seconds' in stickinessAttri.values():
                                        td = datetime.timedelta(seconds=int(stickinessAttri["Value"]))
                                        print(f'    StickinessDuration: {td}')                            
                            elif stickinessAttri["Value"] == "app_cookie":
                                for stickinessAttri in tg_attribute["Attributes"]:
                                    if 'stickiness.app_cookie.duration_seconds' in stickinessAttri.values():
                                        td = datetime.timedelta(seconds=int(stickinessAttri["Value"]))
                                        print(f'    StickinessDuration: {td}')
                                for stickinessAttri in tg_attribute["Attributes"]:
                                    if 'stickiness.app_cookie.cookie_name' in stickinessAttri.values():
                                        print(f'    StickinessAppName: {stickinessAttri["Value"]}')
        print()


def return_sg_name(sg_id: str):
    client = boto3.client('ec2')
    response = client.describe_security_groups(
        GroupIds=[
            sg_id
        ]
    )
    return (response['SecurityGroups'][0]['GroupName'])


def return_acm_name(acm_id: str):
    client = boto3.client('acm')

    acm_list = client.list_certificates(
        CertificateStatuses=[
            'ISSUED'
        ]
    )
    for CertificateSummaryList in acm_list['CertificateSummaryList']:
        if acm_id in CertificateSummaryList['CertificateArn']:
            return (CertificateSummaryList['DomainName'])
        else:
            continue

    return ("None")


def return_instance_name(instance_id: str):
    client = boto3.client('ec2')

    response = client.describe_instances(
        InstanceIds=[
            instance_id
        ]
    )
    for Ec2Name in response["Reservations"][0]["Instances"][0]["Tags"]:
        if 'Name' in Ec2Name.values():
            return (Ec2Name["Value"])
        else:
            continue
    return (instance_id)


if __name__ == '__main__':
    main()

出力イメージ

python3 output_alb_status.py ubukata-albでコマンドを実行することで、以下のような設定を取得できます。
※ 出力イメージ用の設定パラメーターは適当です。あくまで出力イメージように設定しているため、パラメーターが適切でない場合があります。

###### ALB Parameter #####
  LoadBalancerName : ubukata-alb
  Scheme           : internet-facing
  IpAddressType    : ipv4
  Subnet1
    SubnetID       : subnet-XXXXXXXXXXXXXXXX
    AZ_Name        : ap-northeast-1a
  Subnet2
    SubnetID       : subnet-XXXXXXXXXXXXXXXX
    AZ_Name        : ap-northeast-1c
  SecurityGroup
    SG0            : ubukata-sg-pub

  Attribute
    DeletProtection: false
    IdleTimeOut    : 60
    HTTP2Enable    : true

  AccessLog
    LogEnable     : false
    Backet        :
    Prefix        :

  Listener
    Listener0
      Protocol    : HTTPS
      Port        : 443
      Cert0       : ubukata.xxxx.xxxx.hoge.jp
      SslPolicy   : ELBSecurityPolicy-TLS13-1-2-2021-06

    ListerRule 0-0
      Priority     : 1
      Conditions
        host-header: ['hoge.example.com']
        source-ip  : {'Values': ['172.16.0.0/24']}
      Actions
        forward    : ubukata-tg-1
        Weight     : 1
        Stikiness  : False
        forward    : ubukata-tg-2
        Weight     : 2
        Stikiness  : False

    ListerRule 0-1
      Priority     : 2
      Conditions
        source-ip  : {'Values': ['192.168.0.2/32']}
      Actions
        FixResponse: {'MessageBody': 'not found', 'StatusCode': '404', 'ContentType': 'text/plain'}

    ListerRule 0-2
      Priority     : 3
      Conditions
        path-patter: ['/hoge/test/*']
      Actions
        FixResponse: {'MessageBody': 'sorry', 'StatusCode': '503', 'ContentType': 'text/plain'}

    ListerRule 0-3
      Priority     : 4
      Conditions
        http-header: {'HttpHeaderName': 'aa', 'Values': ['hoge']}
      Actions
        Redirect   : {'Protocol': 'HTTPS', 'Port': '10050', 'Host': '#{host}', 'Path': '/#{path}', 'Query': '#{query}', 'StatusCode': 'HTTP_301'}

    ListerRule 0-4
      Priority     : default
      Conditions
      Actions
        forward    : ubukata-tg-1
        Weight     : 1
        Stikiness  : False


    Listener1
      Protocol    : HTTP
      Port        : 80
      Cert        : None

    ListerRule 1-0
      Priority     : default
      Conditions
      Actions
        forward    : ubukata-tg-1
        Weight     : 1
        Stikiness  : False



###### TG Parameter 0 #####
  TargetGroupName  : ubukata-tg-1
  TargetType       : instance
  Protocol         : HTTP
  Port             : 80

  HealthCheck
    Protocol       : HTTP
    Path           : /
    Port           : traffic-port
    Threshold      : 5
    UnHhealtyTH    : 2
    Timeout        : 5
    Interval       : 30
    SuccessCode    : 200

  HealthCheckTarget
    Target 0       : ubukata-windows
    Target 0 Health: unhealthy

  Attribute
    DerectionDelay : 300
    SlowStart      : 0
    LbAlgorithm    : round_robin
    Stickiness     : false

###### TG Parameter 1 #####
  TargetGroupName  : ubukata-tg-2
  TargetType       : instance
  Protocol         : HTTP
  Port             : 80

  HealthCheck
    Protocol       : HTTP
    Path           : /index.html
    Port           : traffic-port
    Threshold      : 5
    UnHhealtyTH    : 2
    Timeout        : 5
    Interval       : 30
    SuccessCode    : 200

  HealthCheckTarget
    Target 0       : ubukata-ec2-rhel
    Target 0 Health: healthy

  Attribute
    DerectionDelay : 300
    SlowStart      : 0
    LbAlgorithm    : round_robin
    Stickiness     : false