Как связать и отправить с IP-адреса правила перенаправления Google Cloud?

Я следил за инструкциями Использование переадресации протоколов на Виртуальной платформе Google. Итак, теперь у меня есть что-то вроде этого:

$ gcloud compute forwarding-rules list
NAME    REGION    IP_ADDRESS      IP_PROTOCOL  TARGET
x-fr-1  us-west1  104.198.?.??    TCP          us-west1-a/targetInstances/x-target-instance
x-fr-2  us-west1  104.198.?.??    TCP          us-west1-a/targetInstances/x-target-instance
x-fr-3  us-west1  104.198.??.???  TCP          us-west1-a/targetInstances/x-target-instance
x-fr-4  us-west1  104.198.??.???  TCP          us-west1-a/targetInstances/x-target-instance
x-fr-5  us-west1  104.198.?.???   TCP          us-west1-a/targetInstances/x-target-instance

(Примечание: имена были изменены, а вопросительные знаки были заменены. Я не уверен, что важно сохранить эти личные, но лучше безопасные, чем извините.)

Мой экземпляр "x" находится в "x-target-instance" и имеет пять правил пересылки "x-fr-1" через "x-fr-5". Я запускаю nginx на "x", и я могу получить к нему доступ с любого из 6 внешних IP-адресов (1 для экземпляра + 5 правил пересылки). Пока что так хорошо.

Мне сейчас интересно привязать сервер к этим внешним IP-адресам. Для изучения я попытался использовать Python:

import socket
import time

def serve(ip_address, port=80):
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.bind((ip_address, port))
    try:
        sock.listen(5)
        while True:
            con, _ = sock.accept()
            print con.getpeername(), con.getsockname()
            con.send(time.ctime())
            con.close()
    finally:
        sock.close()

Теперь я могу привязать "0.0.0.0", и я получаю интересные результаты:

>>> serve("0.0.0.0")
('173.228.???.??', 57288) ('10.240.?.?', 80)
('173.228.???.??', 57286) ('104.198.?.??', 80)

Когда я общаюсь с сервером на его внешнем IP-адресе, метод getsockname возвращает внутренний IP-адрес экземпляра. Но когда я связываюсь с сервером по внешнему IP-адресу, используемому правилом пересылки, методы "getsockname" возвращают внешний IP-адрес.

Хорошо, теперь я связываю внутренний IP-адрес экземпляра:

>>> serve("10.240.?.?")
('173.228.???.??', 57295) ('10.240.?.?', 80)

Снова я могу общаться с сервером по его внешнему IP-адресу, а метод getsockname возвращает внутренний IP-адрес экземпляра. Это кажется немного странным.

Кроме того, если я пытаюсь связать внешний IP-адрес экземпляра:

>>> serve("104.198.?.??")
error: [Errno 99] Cannot assign requested address

Затем я получаю сообщение об ошибке.

Но если я попытаюсь связать внешние IP-адреса, используемые правилами пересылки, а затем сделать запрос:

>>> serve("104.198.??.???")
('173.228.???.??', 57313) ('104.198.??.???', 80)

Он работает.

Наконец, я смотрю "ifconfig":

ens4      Link encap:Ethernet  HWaddr 42:01:0a:??:??:??  
          inet addr:10.240.?.?  Bcast:10.240.?.?  Mask:255.255.255.255
          inet6 addr: fe80::4001:???:????:2/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1460  Metric:1
          RX packets:37554 errors:0 dropped:0 overruns:0 frame:0
          TX packets:32286 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:41201244 (41.2 MB)  TX bytes:3339072 (3.3 MB)

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:9403 errors:0 dropped:0 overruns:0 frame:0
          TX packets:9403 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1 
          RX bytes:3155046 (3.1 MB)  TX bytes:3155046 (3.1 MB)

И я вижу только два интерфейса. Очевидно, что возможности Google Cloud Platform Networking превысили то, что я помню, из моего класса Computer Networking в колледже. Подводя итог моим наблюдениям:

  • Если я хочу привязываться к внешнему IP-адресу экземпляра, я связываю его внутренний IP-адрес.
  • Процесс, связанный с внутренним IP-адресом экземпляра, не может различать IP-адрес назначения между внутренними или внешними IP-адресами экземпляра.
  • Один сетевой адаптер "ens4" принимает пакеты, привязанные к любому из внешних IP-адресов экземпляра 6.

И вот мои вопросы:

  • Почему я не могу связать внешний IP-адрес экземпляра?
  • Как я могу привязывать внешние IP-адреса, используемые правилами пересылки, когда у меня нет связанных сетевых адаптеров?
  • Если я хочу ограничить доступ SSH к внешнему IP-адресу экземпляра, должен ли я настроить SSH для привязки внутреннего IP-адреса?
  • Если я настрою прокси-сервер HTTP на одном из внешних IP-адресов, используемых правилом пересылки, каким будет исходный IP-адрес прокси-запроса?
  • Наконец, и это может быть ошибка, почему список правил пересылки пуст в веб-интерфейсе в https://console.cloud.google.com/networking/loadbalancing/advanced/forwardingRules/list?project=xxx, когда я вижу их с "gcloud compute forwarding-rules list"?

Ответ 1

  • это не в локальной таблице маршрутизации ('ip route show table local') [вы могли бы, конечно, добавить его (например, "ip address add x.x.x.x/32 dev ens4" ), но делать это не принесет вам много пользы, поскольку никакие пакеты не будут доставлен на вашу виртуальную машину, используя этот адрес назначения - см. ниже...]
  • поскольку перенаправленные адреса были добавлены в вашу локальную таблицу маршрутизации ('ip route show table local')
  • вы могли бы [хотя заметить, что это ограничит доступ к ssh для внешних клиентов, ориентированных на внешний IP-адрес, или для клиентов в вашей виртуальной сети, предназначенных для внешнего или внутреннего IP-адреса]. Однако, как уже отмечалось, может быть более важно ограничить разрешенные адреса клиентов (а не адрес сервера), и для этого брандмауэр будет более эффективным.
  • это зависит от того, куда отправляется адрес прокси-запроса. Если он является внутренним для вашей виртуальной сети, то это будет внутренний IP-адрес виртуальной машины, иначе NAT-ed (вне вашей виртуальной машины) будет внешним IP-адресом VM.
  • На этой странице есть несколько вкладок - в двух из которых перечислены различные классы правил пересылки ( "глобальные правила пересылки" и "правила пересылки" ). По общему признанию, несколько сбивает с толку: P

Еще одна вещь, которая немного запутывает - при отправке пакетов на вашу виртуальную машину с использованием внешнего IP-адреса в качестве адреса назначения сущность, находящаяся за пределами виртуальной машины (считая ее виртуальным коммутатором/маршрутизатором/устройством NAT), автоматически изменяет назначение внутренний IP до того, как пакет поступит в драйвер virtio для виртуальной сетевой платы - так что вы ничего не можете сделать, чтобы изменить это поведение. Однако пакеты, адресованные IP-адресу правила пересылки, не являются NAT-ed (как вы видели).

Надеюсь, что это поможет!