すべてのプロダクト
Search
ドキュメントセンター

Elastic Compute Service:PrivateLink を使用して不要なパブリックネットワーク通信を削減する

最終更新日:Nov 02, 2025

VPC 間またはアカウント間のサービスアクセスには、PrivateLink を使用してインターネットの代わりにプライベートネットワーク経由でサービスにアクセスできます。これにより、インターネットへの露出が減り、ネットワークセキュリティが向上します。Server Load Balancer (SLB) サービスをプライベートアクセスに使用する場合、Proxy Protocol v2 を有効にできます。これにより、リクエストのソースである Virtual Private Cloud (VPC) ID と PrivateLink エンドポイント ID を取得して、ネットワークアクセスをより適切に制御できます。

セキュリティリスク

クラウド環境では、自社構築のデータベースプラットフォームや AI 推論アプリケーションなどのサービス、および Object Storage Service (OSS) などの Alibaba Cloud サービスは、アクセスを容易にするために、Elastic IP アドレス (EIP) またはパブリックエンドポイントで構成されることがよくあります。この方法は便利ですが、サービスを直接インターネットに公開することになります。これにより、深刻なセキュリティリスクが生じます。

  1. パブリックネットワーク攻撃のリスク: パブリックネットワークに公開されているサービスはすべて攻撃の標的になる可能性があります。DDoS 攻撃、アプリケーションの脆弱性スキャンと悪用、ブルートフォース攻撃などの脅威に直面します。

  2. ID なりすましのリスク: 従来のインターネットサービスは、主にユーザー名とパスワード認証に依存しています。認証情報が漏洩した場合、攻撃者は世界中のどこからでも正当なユーザーになりすまし、データに不正にアクセス、盗難、または改ざんする可能性があります。パブリックアクセスモデルでは、リクエストのネットワークソースを効果的に制限することはできません。

  3. データ漏洩チャネル: 社内の従業員が個人アカウントを使用して、OSS などの Alibaba Cloud サービスのパブリックエンドポイントを介して、内部ネットワークから企業のコアデータをアップロードおよび漏洩させる可能性があります。通信はパブリックネットワークを介して行われるため、企業のネットワークポリシーを効果的に施行することは困難です。

ベストプラクティス

同一ゾーン内での VPC 間アクセスに PrivateLink を使用する

説明: Web サービスなどのネットワークサービスは、VPC2 の ECS インスタンスにデプロイされます。VPC1 と VPC2 の間に PrivateLink 接続が作成されます。これにより、VPC1 からプライベート IP アドレス (エンドポイント) を使用してネットワークサービスにアクセスできます。

: PrivateLink を使用するには、エンドポイント (サービス利用者) とエンドポイントサービス (サービスプロバイダー) が同じゾーンにある必要があります。より具体的には、エンドポイントがデプロイされているゾーンは、エンドポイントサービスリソースがデプロイされているゾーンのサブセットである必要があります。たとえば、エンドポイントサービスがゾーン A とゾーン B にデプロイされている場合、エンドポイントはゾーン A またはゾーン B でのみ作成できます。

コアステップ:

  1. サーバー側 (サービスプロバイダー) の構成

    1. ロードバランサーの作成: VPC2 で、プライベート Classic Load Balancer (CLB) や Network Load Balancer (NLB) など、PrivateLink をサポートする SLB インスタンスを作成します。バックエンドサーバーグループとリスナーを構成します。

    2. エンドポイントサービスの作成: PrivateLink コンソールで、エンドポイントサービスを作成します。前のステップで作成した SLB インスタンスに関連付けます。

    3. サービスホワイトリストの構成 (アカウント間アクセスのみ): VPC1 が別の Alibaba Cloud アカウントに属している場合は、アカウントの UID をエンドポイントサービスのサービスホワイトリストに追加します。

    4. 接続リクエストの承認: クライアントが接続を開始した後、エンドポイントサービスの [接続] タブに移動します。保留中の接続リクエストを見つけて承認します。作成時にサービスが自動的に接続を承認するように設定することもできます。

  2. クライアント側 (サービス利用者) の構成

    1. エンドポイントの作成: VPC1 で、エンドポイントを作成します。作成中に、サーバー側で作成されたエンドポイントサービスを選択します。

    2. ネットワークの構成: エンドポイント用に VPC1 で vSwitch とセキュリティグループを選択します。これにより、VPC1 のどのリソースがエンドポイントにアクセスできるかを制御します。

    3. エンドポイントの詳細の取得: エンドポイントが作成されると、プライベートドメイン名と IP アドレスが生成されます。

    4. アクセスの開始: サービスプロバイダーが接続を承認した後、VPC1 のアプリケーションはこのドメイン名または IP アドレスを使用して VPC2 のサービスにアクセスできます。

詳細については、「プライベートネットワーク経由で Alibaba Cloud サービスにアクセスする」をご参照ください。

Proxy Protocol を使用してアクセス可能な VPC とそのプライベート IP アドレスを制御する

PrivateLink を介してサービスを提供する場合、サーバーは、どのエンドポイントまたは VPC から来たかなど、ネットワークリクエストの真のソースを識別できます。これにより、サービスはセキュリティルールを設定できます。たとえば、ユーザーアカウントを正当なプライベートネットワーク内でのみ使用するように制限できます。つまり、正当な VPC からのアクセスのみを受け入れます。アカウントの認証情報が漏洩した場合でも、これにより、インターネットや不正なネットワークからサービスにアクセスするためにアカウントが使用されるのを防ぐことができます。

同一ゾーン内での VPC 間アクセスに PrivateLink を使用する」の手順に従い、サーバー側のアプリケーションがリクエストのソース VPC を識別し、この情報に基づいてアクセス制御を実装できるようにします。

  1. Proxy Protocol v2 の有効化: サーバー側の NLB リスナーで Proxy Protocol v2 を有効にし、VPC ID とエンドポイント ID をサブスクライブします。

    # Alibaba Cloud CLI を使用して、指定されたリスナーに対して Proxy Protocol v2 を有効にし、VPC ID とエンドポイント ID をサブスクライブします
    aliyun nlb UpdateListenerAttribute \
         --ListenerId lsn-xxxxxxxxxxxxxxxx \
         --ProxyProtocolEnabled true \
         --ProxyProtocolV2Config '{"Ppv2VpcIdEnabled":true,"Ppv2PrivateLinkEpIdEnabled":true}' \
         --RegionId cn-hangzhou

    --ListenerId: この例で Web サービス用に作成されたリスナーの ID。

    --ProxyProtocolEnabled: true は、Proxy Protocol が有効になっていることを示します。注: このプロトコルは、TCP ハンドシェイク後の最初のパケットでクライアント接続情報を渡します。バックエンドサービスはこのプロトコルをサポートしている必要があります (構成についてはステップ 2 を参照)。そうしないと、サービスが中断されます。

    --ProxyProtocolV2Config: Alibaba Cloud が定義した TLV フィールドを追加します。この例では、ソースネットワークの VPC ID と PrivateLink エンドポイント ID をサブスクライブします。image.pngimage.png対応する TLV 解析は次のとおりです。

    意味/内容

    元の内容

    プロトコルヘッダー

    Proxy Protocol の固定シグネチャ

    0d0a0d0a000d0a515549540a

    バージョン 2、PROXY コマンド

    21

    TCP/IPv4

    11

    次のデータは 84 バイト長です

    0054

    アドレス情報

    ソース IP: 10.0.0.14

    0a00000e

    宛先 IP: 10.0.0.15

    0a00000f

    ソースポート: 59074

    e6c2

    宛先ポート: 80

    0050

    TLV1

    タイプ 03

    03

    4 バイト

    0004

    0764b56b

    0764b56b

    TLV2

    タイプ e1 (カスタムタイプ)

    e1

    24 バイト

    0018

    PrivateLink エンドポイント ID:

    ep-bp1i288487e586152d4b

    0265702d6270316932383834383765353836313532643462

    TLV3

    タイプ e1 (カスタムタイプ)

    e1

    26 バイト

    001a

    VPC ID:

    vpc-bp179qeke0wzo1mr8bxhl

    017670632d627031373971656b6530777a6f316d72386278686c

    TLV4

    04 (PP2_TYPE_NETNS)、ネットワーク名前空間を渡すために使用

    04

    6 バイト

    0006

    000000000000

    000000000000

  2. Web サービスで NGINX を使用している場合は、次のように NGINX を構成して Proxy Protocol をサポートします。

    (NGINX Plus R16 以降、またはオープンソース NGINX 1.13.11 以降は、Proxy Protocol v2 をサポートしています)

    server {
        listen 80 proxy_protocol;   # Proxy Protocol v1/v2 を有効にする
        # その他の構成...
    }

    この方法では、nginx はポート 80 で Proxy Protocol TLV を自動的に解析しますが、nginx の標準バージョンは TLV から IP アドレスをフェッチすることしかサポートしていません。

    Alibaba のカスタム VPC ID と PrivateLink エンドポイント ID を処理するには、Lua 拡張機能が必要です。

    次のコードは、ソケットからパケットを読み取り、TLV バッファーを解析することによって TCP 接続を処理する nginx.conf 用の Lua プラグインの例です。

    リクエストコンテキストに PrivateLink エンドポイント ID を保存します。`/login` リクエストの場合、この ID が正しいことを確認します。以下は Lua コードの例です。

    stream {
      server{
      listen 80;  # proxy_protocol を有効にしないでください。以下の Lua コードで処理させます。
      preread_by_lua_block {
         -- 1. 固定の 16 バイトのプロトコルヘッダーを読み取ってみます
         local sock = ngx.req.socket(true)
         local header, err = sock:receive(16)
    
         if not header then
            ngx.log(ngx.ERR, "failed to receive proxy protocol header: ", err)
            return
         end
    
         -- 2. プロトコルシグネチャ (12 バイト) を確認します
         if string.sub(header, 1, 12) ~= "\x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A" then
             -- Proxy Protocol でない場合は、読み取ったデータをバッファーに戻して、元のリクエストが破損しないようにします
              sock:setreused(header)
                    return
        end
    
        -- 3. プロトコルヘッダーの残りの部分を解析します
        local ver_cmd = string.byte(header, 13) -- バージョンとコマンド
        local family = string.byte(header, 14) -- アドレスファミリーとプロトコル
        local len = string.byte(header, 15) * 256 + string.byte(header, 16) -- 可変部分の全長
        if len == 0 then
           -- アドレスまたは TLV 情報がないため、直接戻ります
           return
        end
    
        -- 4. 可変長部分 (アドレスと TLV を含む) を読み取ります
        local variable_part, err = sock:receive(len)
        if not variable_part or #variable_part < len then
           ngx.log(ngx.ERR, "failed to read variable part (address + tlvs): ", err)
           return
        end
    
        -- 5. アドレスファミリーに基づいてアドレス情報の長さを決定します
        local addr_len = 0
        local protocol = family & 0x0F
        local address_family = family >> 4
    
        if address_family == 1 then -- AF_INET (IPv4)
            addr_len = 12
        elseif address_family == 2 then -- AF_INET6 (IPv6)
            addr_len = 36
        elseif address_family == 3 then -- AF_UNIX
            addr_len = 216
        end
    
        -- 6. アドレス情報と TLV データを分離します
        local address_block = string.sub(variable_part, 1, addr_len) -- 必要に応じてアドレス情報を解析できます
        local tlv_string = string.sub(variable_part, addr_len + 1)
    
        -- 7. TLV データを解析します
        local tlvs = {}
        local pos = 1
        while pos <= #tlv_string do
            -- 少なくとも 3 バイト (タイプ、長さ) があることを確認します
            if pos + 2 > #tlv_string then
                ngx.log(ngx.ERR, "malformed TLV data: not enough bytes for type and length")
                break
            end
    
            local tlv_type = string.byte(tlv_string, pos)
            local tlv_length = string.byte(tlv_string, pos + 1) * 256 + string.byte(tlv_string, pos + 2)
        
            -- 値の長さが境界を超えないことを確認します
            if pos + 2 + tlv_length > #tlv_string then
                ngx.log(ngx.ERR, "malformed TLV data: length exceeds available data")
                break
            end
        
            local tlv_value = string.sub(tlv_string, pos + 3, pos + 2 + tlv_length)
                        
            table.insert(tlvs, {
                type = tlv_type,
                length = tlv_length,
                -- 保存と表示を容易にするために、バイナリ値を Base64 でエンコードします
                value = ngx.encode_base64(tlv_value) 
             })
             pos = pos + 3 + tlv_length
       end
    
       -- 8. 解析された TLV を ngx.ctx にキャッシュします
       -- ngx.ctx はリクエストごとに一意であり、データを渡す標準的な方法です
      if #tlvs > 0 then
          ngx.ctx.proxy_protocol_tlvs = tlvs
          -- 例: ログに記録したい場合は、http セクションの log_format で $proxy_protocol_tlvs 変数を使用できます
          -- http ブロックで `lua_set $proxy_protocol_tlvs 'return ngx.var.proxy_protocol_tlvs_json';` を定義する必要があります
          -- そして `preread_by_lua_block` で `ngx.var.proxy_protocol_tlvs_json = cjson.encode(ngx.ctx.proxy_protocol_tlvs)` を定義します
      end
      }
      proxy_pass localhost:8080;   # 後続の HTTP リクエストを HTTP サーバーに渡します
      }
    }
    
    http {
        server {
            listen 8080;
    
            # /login リクエストを処理するための専用の場所
            location /login {
                access_by_lua_block {
                    local expected_value = "some value"
                    -- ストリームレイヤーから渡された 2 番目の TLV (Base64 エンコード) の値を NGINX 変数から取得します
                    local privateLinkEndId = ngx.var.pp_tlv2_value
                    
                    -- 値が期待どおりでない場合はリクエストを拒否します
                    if received_value ~= expected_value then
                        ngx.log(ngx.ERR, "Access to /login denied: TLV value mismatch. Expected '", 
                                expected_value, "', got '", received_value, "'")
                        return ngx.exit(ngx.HTTP_FORBIDDEN)
                    end
                    -- 検証が成功した場合、リクエストは引き続き処理されます
                }
                
                # 検証が成功した後、リクエストをバックエンドの Python プログラムに転送します
                proxy_pass http://your_python_backend;
            }
    
            # 他のすべてのリクエストを処理します
            location / {
                # ここでは、ニーズに基づいてアクセスを許可するかどうかを決定できます
                # たとえば、バックエンドに直接転送します
                proxy_pass http://your_python_backend;
            }
        }
    
        # Python バックエンドサービスのアップストリーム定義
        upstream your_python_backend {
            server 127.0.0.1:5000; # バックエンドプログラムがポート 5000 で実行されていると仮定します
        }
    }

PrivateLink を使用して Alibaba Cloud サービスにアクセスする

一部の Alibaba Cloud サービスは、PrivateLink を介したアクセスをサポートしており、プライベートネットワークで承認済みアカウントを構成することで、パブリックネットワークアクセスのセキュリティリスクを回避します

個人アカウントを使用すると、企業のデータが漏洩するリスクがあります。また、企業アカウントを構成して、正当なプライベートネットワークからのアクセスのみを許可し、アカウントが侵害された場合の外部からの悪用を防ぐこともできます。

一部の Alibaba Cloud サービスは現在、PrivateLink を介したアクセスをサポートしており、パブリックネットワークアクセスのリスクを回避します。1) プライベートネットワークでの使用が許可されている正当なアカウントを構成します。これにより、個人アカウントを使用したデータ漏洩のリスクを防ぎます。2) 企業アカウントを、正当なプライベートネットワークからのみアクセスできるように構成します。これにより、認証情報が漏洩した場合にアカウントが外部から悪用されるのを防ぎます。

  1. Alibaba Cloud サービスのエンドポイントを作成する: PrivateLink コンソールで、OSS など、アクセスする必要のある Alibaba Cloud サービスのゲートウェイエンドポイントを作成します。エンドポイントを企業の VPC とルートテーブルに関連付けます。

    内部の VPC とルートテーブルに関連付けることができます。

  2. エンドポイントアクセスポリシーを構成する: エンドポイントのポリシーで、企業の Alibaba Cloud アカウント配下のリソースアクセスマネジメント (RAM) ID (ユーザーまたはロール) のみにアクセスを制限します。これにより、従業員の個人アカウントなどの他のアカウントが、このプライベートチャネルを介して OSS にアクセスするのを防ぎます。

    これにより、従業員の個人アカウントなどの他のアカウントが、このプライベートチャネルを介して OSS にアクセスするのを防ぎます。

    エンドポイントアクセスポリシーで、Alibaba Cloud サービスへのアクセスを、企業に属するアカウントのみに制限します。

  3. RAM ポリシーを構成する (オプションの機能強化): より強力な制御のために、RAM ユーザーまたはロールのポリシーを構成できます。たとえば、OSS へのアクセスが指定された VPC からのものであることを強制できます。

    指定された VPC から OSS にアクセスする必要があります。

コンプライアンス機能

チェック: VPC から Alibaba Cloud のパブリック IP アドレスへのアクセスがあるかどうかを判断する

開始する前に、PrivateLink を使用して最適化できるパブリックネットワーク通信が環境にないか確認できます。これを行うには、VPC フローログを分析して、VPC から Alibaba Cloud のパブリック IP アドレスへのアウトバウンドトラフィックを見つけます。

VPC から Alibaba Cloud サービスのパブリック IP アドレスへのアウトバウンドトラフィック。

ステップ:

  1. VPC フローログを有効にする: コアビジネスが存在する VPC のフローログ機能を有効にします。ログを Simple Log Service (SLS) に配信します。

  2. アウトバウンドトラフィックを分析する: SLS で、VPC フローログをクエリし、アウトバウンドトラフィック (direction = out) をフィルターします。

  3. フィルターと特定:

    • 応答パケットをフィルターする: ノイズを減らすために、宛先ポートが 1024 未満のトラフィックや、通常のサービス応答の一部である他のトラフィックを除外します。

    • Alibaba Cloud のパブリック IP アドレスを特定する: ipip.net などのツールを使用して、ログ内の宛先 IP アドレス (dstaddr) の所有権をクエリします。Alibaba Cloud に属するパブリック IP アドレスに焦点を当てます。

      Alibaba Cloud に属するパブリック IP アドレスには特に注意してください。

    • ソース ECS インスタンスを特定する: フローログの `vm-id` フィールドを使用して、アクセスを開始した ECS インスタンスを特定します。

ログ分析のサンプル:

これらのタイプのログを分析することで、どのインスタンスがパブリックネットワーク経由で他のクラウドリソースにアクセスしているかを特定できます。

image.png

結果の判断:

  • クエリされた宛先のパブリック IP アドレスが、OSS や ECS などの Alibaba Cloud サービスのパブリックエンドポイントである場合は、PrivateLink エンドポイントに切り替えることを強くお勧めします。

    アクセスノード

  • 宛先のパブリック IP アドレスが、アカウント内の別の VPC にあるサービス (EIP や SLB など) を指している場合は、この VPC 間の通信シナリオに PrivateLink を使用できます。

    これは最適化のための理想的なシナリオです。