Skip to content

Nebula Overlay Networking

A scalable overlay networking tool with a focus on performance, simplicity and security

Nebula is an overlay networking tool designed to be fast, secure, and scalable. Connect any number of hosts with on-demand, encrypted tunnels that work across any IP networks and without opening firewall ports.

Features

  • 멀티 클라우드/로케이션에 퍼져있는 수많은 노드를 연결해주는 도구.
  • 간결하면서도 성능과 보안에 중점을 두고 개발.
  • 슬랙이 초기엔 IPSec을 이용하다 자체개발해서 2년째 사용중.
  • Noise Protocol Framework 에 기반한 상호 인증된 P2P 소프트웨어 정의 네트워크.

클라우드 서비스들이 자체적인 시큐리티그룹들을 지원하지만, 각 서비스와 지역에만 종속적이고, 여러 서비스들간에 연결이 가능하지 않음. 이를 해결하기 위해 암호화,시큐리티그룹,인증서,터널링 등을 한데 병합한 솔루션.

  • 호스트간 암호화된 연결 지원
  • 서비스 비 종속 - 클라우드/데이터센터/개인노트북 이든 상관없음
  • 고수준 트래픽 필터링
  • 강력한 아이덴티티 제공
  • 최대한 빠르게
  • 네트웍 변경에 대한 테스트 가능

Components of a Nebula network

등대 (Lighthouse)

Nebula에서 Lighthouse(등대)는 다른 모든 Nebula 호스트를 추적하고 Nebula 네트워크 내에서 서로를 찾을 수 있도록 돕는 Nebula 호스트입니다.

오버레이 네트워크에서 최소한 하나의 호스트는 호스트가 Lighthouse(등대)여야 합니다. Lighthouse 는 서로에 대한 경로를 검색하고 NAT 통과를 지원합니다.

인증 기관 (Certificate Authority; CA)

가장 간단한 형태의 Nebula 인증 기관(CA)은 두 개의 파일, 즉 CA 인증서와 관련 개인 키로 구성됩니다.

CA 인증서는 네트워크의 모든 호스트에 배포되고 신뢰됩니다.

CA 개인 키는 배포되어서는 안 되며, Nebula 네트워크에 호스트를 추가하는 데 사용되지 않을 때는 오프라인으로 유지될 수 있습니다.

호스트 (Hosts)

Nebula 호스트는 단순히 네트워크의 단일 노드(예: 서버, 노트북, 휴대폰, 태블릿)입니다.

인증 기관은 Nebula 네트워크에 추가된 각 호스트에 대한 키에 서명하는 데 사용됩니다.

호스트 인증서 (Host Certificate) 에는 이름, IP 주소, 그룹 멤버십 및 호스트에 대한 기타 여러 세부 정보가 포함되어 있습니다.

개별 호스트는 자신의 인증서를 수정할 수 없습니다. 수정하면 인증서가 무효화되기 때문입니다. 이를 통해 우리는 호스트가 Nebula 네트워크 내에서 다른 호스트를 가장할 수 없다는 것을 신뢰할 수 있습니다. 각 호스트에는 Nebula 터널이 생성될 때 해당 호스트의 신원을 확인하는 데 사용되는 자체 개인 키가 있습니다.

다운로드 및 설치

sudo -s
curl -L https://github.com/slackhq/nebula/releases/download/v1.9.1/nebula-linux-amd64.tar.gz | tar xzf - -C /usr/bin

첫 번째 인증 기관 만들기

Nebula는 v1.7.0부터 CA 개인 키의 내장 암호화를 제공합니다. 암호화된 스토리지(예:Ansible Vault또는AWS Secrets Manager)에 프라이빗 키를 저장할 계획이 없다면 내장된 암호화를 사용하는 것이 좋습니다.
Nebula 개인 키를 암호화하려면 CA를 생성할 때 ``-encrypt`` 플래그를 전달하면 암호를 입력하라는 메시지가 표시됩니다. 안전하게 보관하세요. 암호화된 CA 키를 사용하여 호스트에 서명할 때마다 이를 묻는 메시지가 표시됩니다.
Nebula는 키 파생을 위해Argon2id와함께AES-256-GCM암호화를 사용합니다.
기본Argon2매개변수는 Argon2 RFC (1회 반복, 4레인 병렬 처리, 2GiB RAM)의 "FIRST RECOMMENDED" 제안에서 가져옵니다.
고유한 매개변수를 선택하려면 ``-argon-iterations``, ``-argon-parallelism``및 ``-argon-memory`` CLI 플래그를 사용합니다.

Nebula는 인증 기관을 사용하여 Nebula 네트워크 내의 개별 호스트를 식별합니다. 자신만의 Nebula 네트워크를 만드는 첫 번째 단계는 조직에 대한 인증 기관을 만드는 것입니다. Nebula 네트워크에 새 호스트를 추가하면 조직에서 호스트를 신뢰할 수 있음을 증명하는 자격 증명을 생성하는 데 인증 기관이 사용됩니다.

./nebula-cert ca -name "Myorganization, Inc"

그러면 현재 디렉터리에 ca.keyca.cert라는 이름의 파일이 생성됩니다.

ca.key 파일은 개별 Nebula 호스트에 대한 인증서에 서명하는 데 사용되는 키이기 때문에 생성할 가장 민감한 파일입니다. 이 파일을 안전한 곳에 저장하세요. 가급적이면 강력한 암호화를 사용하세요.

INFORMATION

기본적으로 이 CA는 1년 만료로 생성되며 서명된 모든 인증서는 CA가 만료되기 1초 전까지 유효합니다. 지속적인 연결을 보장하려면 그 전에 CA 및 인증서를 교체 하도록 경고 또는 달력 이벤트를 설정하십시오!

CA 가 유효한 사용자 지정 기간을 설정하려면 -duration XXhXXmXXs 플래그를 전달하면 됩니다. 예를 들어 -duration 17531h를 사용하면 2년 미만 동안 유효한 CA를 생성합니다.

Building a Nebula network

등대 설립 (Establishing a Lighthouse)

Nebula의 Lighthouse는 호스트가 세계 어디에서나 서로를 찾을 수 있게 해줍니다. Lighthouse는 IP 주소가 변경되어서는 안 되는 Nebula 네트워크의 유일한 호스트입니다.

등대를 운영하려면 컴퓨팅 리소스가 거의 필요하지 않으며 클라우드 호스팅 공급자가 제공하는 가장 저렴한 옵션을 쉽게 사용할 수 있습니다.

어떤 공급자를 사용해야 할지 확실하지 않은 경우, 우리 중 다수는 월 $5의 DigitalOcean droplets 을 등대로 사용했습니다.

인스턴스를 시작한 후에는 Nebula UDP 트래픽(기본 포트 udp/4242)이 인터넷을 통해 인스턴스에 도달할 수 있고 인바운드 방화벽에 의해 차단되지 않는지 확인하세요.

iptables를 사용한다면:

-A INPUT -p udp -m state --state NEW -m udp --dport 4242 -j ACCEPT

Creating Keys and Certificates

여기서는 lighthouse1, laptop, server라는 세 개의 호스트가 있다고 가정합니다.

FQDN을 포함하여 원하는 방식으로 호스트 이름을 지정할 수 있습니다.

또한 인증서를 생성할 때 각 호스트에 대한 Nebula IP 주소를 선택해야 합니다. 이 예에서는 서브넷을 사용하는 Nebula 네트워크를 만들고 192.168.100.x/24이 서브넷 내의 각 호스트에 IP 주소를 할당합니다.

이 예에서는 나중에 Nebula Network 에서 Traffic Rules을 정의하는 데 사용할 수 있는 Nebula Group을 보여줍니다.

./nebula-cert sign -name "lighthouse1" -ip "192.168.100.1/24"
./nebula-cert sign -name "laptop" -ip "192.168.100.5/24" -groups "laptop,ssh"
./nebula-cert sign -name "server" -ip "192.168.100.9/24" -groups "servers"

Configuring Nebula

INFORMATION

다음 예에서는 주소 198.51.100.1을 가상 lighthouse 의 라우팅 가능한 IP로 사용합니다. Nebula 구성 파일을 생성할 때 자신의 등대의 라우팅 가능한 IP를 대체해야 합니다.

Nebula 의 Example Config 를 다운로드 받고, Lighthouse 용 config-lighthouse.yaml와 그 외의 모든 호스트용 config.yaml 파일로 복사하세요:

curl -o config.yml https://raw.githubusercontent.com/slackhq/nebula/master/examples/config.yml
cp config.yml config-lighthouse.yaml
cp config.yml config.yaml

파일을 새로 만들지 말고 예제를 복사한 후 아래에 설명된 부분만 수정하자.

Lighthouse configuration (config-lighthouse.yaml)

Lighthouse 는 am_lighthouse: true가 있는지 확인하면 된다.

일반적으로 등대에는 static_host_map에 항목이 없습니다. 모든 호스트가 자신을 등대에 보고하기 때문입니다. 여러 개의 등대를 사용하는 경우 일반적으로 서로에 대해 알 필요가 없습니다.

static_host_map:

lighthouse:
  am_lighthouse: true

Host configuration (config.yaml)

개별 호스트들은 Lighthouse 가 static_host_map 섹션에 올바르게 정의되어 있고, lighthouse > hosts가 추가되었는지 확인하세요.

static_host_map:
  '192.168.100.1': ['198.51.100.1:4242']

lighthouse:
  am_lighthouse: false
  interval: 60
  # `hosts`는 이 노드가 보고하고 쿼리해야 하는 Lighthouse 호스트 목록입니다.
  # 중요 1: Lighthouse 노드에서는 비어 있어야 합니다.
  # 중요 2: 이는 LIGHTHOUSES의 실제 라우팅 가능한 IP가 아니라 LIGHTHOUSES의 Nebula IP 여야 합니다.
  hosts:
    - '192.168.100.1'

방화벽 구성

예제 구성 파일은 모든 아웃바운드 트래픽을 허용하지만 각 Nebula 호스트에 대한 특정 연결만 허용합니다. 네트워크 내 호스트와의 트래픽을 허용하려면 이러한 설정을 수정해야 합니다.

firewall:
  outbound:
    # Allow all outbound traffic from this node
    - port: any
      proto: any
      host: any

  inbound:
    # Allow icmp between any nebula hosts
    - port: any
      proto: icmp
      host: any

만약 Nebula Network 로 트래픽이 전송되고 iptable을 사용한다면 양 쪽 모두 방화벽 설정을 해야한다.... 개 귀찮게스리..

기본 설정으로 아무런 셋팅이 없으면 In/Out 바운드는 DROP 이다:

firewall:
  outbound_action: drop
  inbound_action: drop

만약 6443/tcp 포트를 열고 싶다면:

firewall:
  inbound:
    - port: 6443
      proto: tcp
      host: any

그리고 필요하다면: iptables -A INPUT -p tcp -m state --state NEW -m tcp --dport 6443 -j ACCEPT

Running Nebula

구성, 인증서 및 키 파일이 생성되면 마지막 단계는 적절한 파일을 각 호스트에 복사하고 Nebula 네트워크를 시작하는 것입니다.

Lighthouse

  1. Lighthouse 에 다음 파일을 복사하세요: nebula 바이너리, config-lighthouse.yaml, ca.crt, lighthouse1.crt, and lighthouse1.key 절대로 ca.key 파일은 복사하면 안됩니다!!!
  2. SSH to your lighthouse.
  3. Create a directory named /etc/nebula on your lighthouse host.
  4. 구성, 인증서, 키 파일들을 적절한 디렉터리로 이동합니다.

mv config-lighthouse.yaml /etc/nebula/config.yaml mv ca.crt /etc/nebula/ca.crt mv lighthouse.crt /etc/nebula/host.crt mv lighthouse.key /etc/nebula/host.key

</syntaxhighlight>

  1. Start Nebula: ./nebula -config /etc/nebula/config.yaml

Hosts

이 예에서는 위에서 생성한 server라는 호스트를 구성합니다. 적절한 파일 이름으로 대체하십시오.

  1. Host 에 다음 파일을 복사하세요: nebula 바이너리, config.yaml, ca.crt, server.crt, and server.key 절대로 ca.key 파일은 복사하면 안됩니다!!!
  2. SSH to the host you've named server.
  3. Create a directory named /etc/nebula on the Nebula host.
  4. Move the configuration, certificates, and key into the appropriate directory.
    • 참고로 예제 구성에서는 호스트 인증서와 키의 이름이 host.crthost.key라고 가정하므로 파일을 적절한 디렉터리로 이동할 때 일부 파일의 이름을 바꿔야 합니다.

mv config.yaml /etc/nebula/config.yaml mv ca.crt /etc/nebula/ca.crt mv server.crt /etc/nebula/host.crt mv server.key /etc/nebula/host.key

</syntaxhighlight>

  1. Start Nebula: ./nebula -config /etc/nebula/config.yaml

파일들 권한 조정

cd /etc/nebula
sudo chmod 600 ca.crt config.yml host.crt host.key
sudo chown root:root ca.crt config.yml host.crt host.key

Verifying it all works

이제 Nebula를 실행하는 다른 호스트에 ping을 보낼 수 있습니다(ICMP가 허용된다고 가정). 예시의 lighthouse 를 PING 하려면 다음을 실행하세요.

ping 192.168.100.1

Relay

INFORMATION

결론만 말하면 통신하려는 양 측 호스트가 모두 Symmetric NAT 안에 감춰져 있다면 결국 이런 방법을 써야 한다.

릴레이 호스트는 두 피어 간에 트래픽을 전달합니다. 이는 두 노드가 서로 직접 통신하는 데 어려움을 겪는 경우 유용할 수 있습니다(예: 일부 NAT에서는 두 노드 간의 직접 연결 설정이 어려울 수 있습니다.)

다른 호스트에 대한 릴레이 역할을 하려면 반드시 am_relay: true(기본값은 false)로 설정되어야 합니다.

릴레이를 사용하려면 해당 호스트가 use_relays: true(기본값은 true)로 설정되어 있어야 합니다.

모든 호스트가 릴레이가 될 수 있습니다. 꼭 등대(Lighthouse)일 필요는 없습니다. 그러나 등대와 마찬가지로 릴레이 노드는 Nebula의 UDP 트래픽 인바운드를 허용하는 공용 인터넷 IP 및 방화벽 규칙을 사용하여 배포되어야 합니다.

relays에 열거된 Nebula IP 목록은 현재 호스트에 패킷을 중계하는 데 사용할 수 있는 릴레이 역할을 할 수 있는 다른 호스트 입니다. 즉, 이 목록의 IP는 구성에서 am_relay: true 로 설정 되어 있어야 합니다. 그렇지 않으면 릴레이 요청을 거부합니다.

이를 통해 호스트는 자신과 "가까운" 릴레이를 지정할 수 있습니다. 예를 들어, 프라이빗 AWS VPC에 일부 Nebula 호스트가 있는 경우 해당 VPC의 피어에 대한 연결을 활성화하는 전용 릴레이 호스트를 설정할 수 있습니다.

릴레이로 릴레이할 수 없습니다. 릴레이(am_relay: true)로 구성된 호스트는 자체 구성에서 다른 호스트를 릴레이로 지정할 수 없습니다.

릴레이 설정 예시:

relay:
  relays:
    - 192.168.100.1
  am_relay: true
  use_relays: true

INFORMATION

relays 주소는 필수 입니다. 또한 릴레이로 접속하려는 호스트는 릴레이 설정이 되어 있어야 한다.

iptables

iptables 방화벽 설정했다면 Nebula 의 config.yml 안에 listen.port 값을 0 을 사용하지 말아라. (문서상의 기본 값인 4242 을 사용한다는 가정으로 진행)

그리고 아래와 같이 설정:

## 통신 프로토콜
-A INPUT -p udp --sport 4242 -j ACCEPT

## VPN 인터페이스를 모두 ACCEPT -> 이 설정은 nebula 의 자체 firewall 설정으로 모두 대체하기 위함.
-A INPUT -i nebula1 -j ACCEPT

보안 관련 문제

작동 원리

Nebula는 중앙 게이트웨이를 거치지 않고 노드가 서로 직접 통신하는 소위 메시 네트워크 입니다. 이는 네트워킹 속성을 영리하게 활용하여 작동합니다.

하루에 수천 번 발생하는 일반적인 네트워킹 흐름은 다음과 같습니다 (터무니없이 단순화됨).

How_Nebula_works_-_flow.png

연결을 설정할 때 클라이언트는 서버의 응답을 위해 포트를 엽니다. 클라이언트와 서버 사이의 방화벽과 라우터는 이 프로세스를 알고 클라이언트로 돌아가는 트래픽이 허용되는지 확인합니다.

Nebula는 이 개방형 포트를 사용하여 방화벽을 교묘하게 통과하고 클라이언트를 서로 직접 연결합니다. 성운 용어로 Lighthouse 라고 불리는 특수 노드 는 클라이언트가 서로를 발견하도록 하는 데 사용됩니다. 이 특수 노드는 공개적으로 연결 가능한 IP 주소를 가져야 하는 유일한 네트워크 구성원입니다. 클라이언트는 먼저 Lighthouse에 연결하고 로컬 포트를 엽니다. 그러나 Lighthouse는 직접 응답하지 않고 대상 클라이언트에게 새로 열린 포트에 응답하도록 지시합니다. 이 과정은 반대쪽에서도 반복됩니다.

How_Nebula_works_-_discovery.png

이는 매우 단순화된 다이어그램입니다. 실제로는 원활한 NAT 통과를 위해 훨씬 더 많은 스푸핑과 속임수가 진행되고 있습니다.

Authentication

WireGuard에 비해 큰 장점 중 하나는 Nebula가 인증을 처리하는 방식입니다. WireGuard는 관리자가 새 클라이언트의 공개 키를 기존 노드의 구성에 통합할 것으로 기대합니다. 이론적으로는 간단하지만 이 접근 방식은 확장성이 뛰어나지 않으며 새 노드를 자동으로 출시하려면 추가 도구가 필요합니다. Tailscale 과 동료는 이러한 복잡성을 관리하는 좋은 방법이지만 추가 서비스와 추상화를 도입하는 대가를 치르게 됩니다.

Nebula는 공개 키 인프라 (PKI) 개념을 활용하여 이 문제를 해결합니다. 중앙 인증 기관 (CA)은 클라이언트의 인증서에 서명합니다. 이러한 인증서는 관리 목적뿐만 아니라 암호화 목적으로도 사용됩니다. 서명에는 노드의 IP 주소뿐만 아니라 허용된 서브넷 및 그룹과 같은 기타 메타데이터도 포함됩니다.

새로운 클라이언트가 Lighthouse에 등록할 때마다 인증 기관에 인증서를 확인하고 인증서에 저장된 IP 주소를 기억합니다. CA 자체는 변경되지 않으므로 Lighthouse는 구성된 후 생성된 클라이언트를 확인할 수 있으며 이러한 변경 사항에 적응할 필요가 없습니다.

내가 적용한 설정

Blackhole#Nebula 항목 참조.

Nebula vs Tailscale

systemd 서비스로 기동하기

/etc/systemd/system/nebula.service 에 파일 저장:

[Unit]
Description=Nebula VPN
After=network.target

[Service]
ExecStart=/path/to/nebula -config /path/to/config.yml
Restart=on-failure

[Install]
WantedBy=multi-user.target

서비스 파일 로드/부팅 시작 등록/실행:

sudo systemctl daemon-reload
sudo systemctl enable nebula
sudo systemctl start nebula

config.yml examples

공식 샘플을 원본으로 수정하자.

curl -o config.yml https://raw.githubusercontent.com/slackhq/nebula/master/examples/config.yml

다운받은 원본은 다음과 같다:

# This is the nebula example configuration file. You must edit, at a minimum, the static_host_map, lighthouse, and firewall sections
# Some options in this file are HUPable, including the pki section. (A HUP will reload credentials from disk without affecting existing tunnels)

# PKI defines the location of credentials for this node. Each of these can also be inlined by using the yaml ": |" syntax.
pki:
  # The CAs that are accepted by this node. Must contain one or more certificates created by 'nebula-cert ca'
  ca: /etc/nebula/ca.crt
  cert: /etc/nebula/host.crt
  key: /etc/nebula/host.key
  # blocklist is a list of certificate fingerprints that we will refuse to talk to
  #blocklist:
  #  - c99d4e650533b92061b09918e838a5a0a6aaee21eed1d12fd937682865936c72
  # disconnect_invalid is a toggle to force a client to be disconnected if the certificate is expired or invalid.
  #disconnect_invalid: true

# The static host map defines a set of hosts with fixed IP addresses on the internet (or any network).
# A host can have multiple fixed IP addresses defined here, and nebula will try each when establishing a tunnel.
# The syntax is:
#   "{nebula ip}": ["{routable ip/dns name}:{routable port}"]
# Example, if your lighthouse has the nebula IP of 192.168.100.1 and has the real ip address of 100.64.22.11 and runs on port 4242:
static_host_map:
  "192.168.100.1": ["100.64.22.11:4242"]

# The static_map config stanza can be used to configure how the static_host_map behaves.
#static_map:
  # cadence determines how frequently DNS is re-queried for updated IP addresses when a static_host_map entry contains
  # a DNS name.
  #cadence: 30s

  # network determines the type of IP addresses to ask the DNS server for. The default is "ip4" because nodes typically
  # do not know their public IPv4 address. Connecting to the Lighthouse via IPv4 allows the Lighthouse to detect the
  # public address. Other valid options are "ip6" and "ip" (returns both.)
  #network: ip4

  # lookup_timeout is the DNS query timeout.
  #lookup_timeout: 250ms

lighthouse:
  # am_lighthouse is used to enable lighthouse functionality for a node. This should ONLY be true on nodes
  # you have configured to be lighthouses in your network
  am_lighthouse: false
  # serve_dns optionally starts a dns listener that responds to various queries and can even be
  # delegated to for resolution
  #serve_dns: false
  #dns:
    # The DNS host defines the IP to bind the dns listener to. This also allows binding to the nebula node IP.
    #host: 0.0.0.0
    #port: 53
  # interval is the number of seconds between updates from this node to a lighthouse.
  # during updates, a node sends information about its current IP addresses to each node.
  interval: 60
  # hosts is a list of lighthouse hosts this node should report to and query from
  # IMPORTANT: THIS SHOULD BE EMPTY ON LIGHTHOUSE NODES
  # IMPORTANT2: THIS SHOULD BE LIGHTHOUSES' NEBULA IPs, NOT LIGHTHOUSES' REAL ROUTABLE IPs
  hosts:
    - "192.168.100.1"

  # remote_allow_list allows you to control ip ranges that this node will
  # consider when handshaking to another node. By default, any remote IPs are
  # allowed. You can provide CIDRs here with `true` to allow and `false` to
  # deny. The most specific CIDR rule applies to each remote. If all rules are
  # "allow", the default will be "deny", and vice-versa. If both "allow" and
  # "deny" IPv4 rules are present, then you MUST set a rule for "0.0.0.0/0" as
  # the default. Similarly if both "allow" and "deny" IPv6 rules are present,
  # then you MUST set a rule for "::/0" as the default.
  #remote_allow_list:
    # Example to block IPs from this subnet from being used for remote IPs.
    #"172.16.0.0/12": false

    # A more complicated example, allow public IPs but only private IPs from a specific subnet
    #"0.0.0.0/0": true
    #"10.0.0.0/8": false
    #"10.42.42.0/24": true

  # EXPERIMENTAL: This option may change or disappear in the future.
  # Optionally allows the definition of remote_allow_list blocks
  # specific to an inside VPN IP CIDR.
  #remote_allow_ranges:
    # This rule would only allow only private IPs for this VPN range
    #"10.42.42.0/24":
      #"192.168.0.0/16": true

  # local_allow_list allows you to filter which local IP addresses we advertise
  # to the lighthouses. This uses the same logic as `remote_allow_list`, but
  # additionally, you can specify an `interfaces` map of regular expressions
  # to match against interface names. The regexp must match the entire name.
  # All interface rules must be either true or false (and the default will be
  # the inverse). CIDR rules are matched after interface name rules.
  # Default is all local IP addresses.
  #local_allow_list:
    # Example to block tun0 and all docker interfaces.
    #interfaces:
      #tun0: false
      #'docker.*': false
    # Example to only advertise this subnet to the lighthouse.
    #"10.0.0.0/8": true

  # advertise_addrs are routable addresses that will be included along with discovered addresses to report to the
  # lighthouse, the format is "ip:port". `port` can be `0`, in which case the actual listening port will be used in its
  # place, useful if `listen.port` is set to 0.
  # This option is mainly useful when there are static ip addresses the host can be reached at that nebula can not
  # typically discover on its own. Examples being port forwarding or multiple paths to the internet.
  #advertise_addrs:
    #- "1.1.1.1:4242"
    #- "1.2.3.4:0" # port will be replaced with the real listening port

  # EXPERIMENTAL: This option may change or disappear in the future.
  # This setting allows us to "guess" what the remote might be for a host
  # while we wait for the lighthouse response.
  #calculated_remotes:
    # For any Nebula IPs in 10.0.10.0/24, this will apply the mask and add
    # the calculated IP as an initial remote (while we wait for the response
    # from the lighthouse). Both CIDRs must have the same mask size.
    # For example, Nebula IP 10.0.10.123 will have a calculated remote of
    # 192.168.1.123
    #10.0.10.0/24:
      #- mask: 192.168.1.0/24
      #  port: 4242

# Port Nebula will be listening on. The default here is 4242. For a lighthouse node, the port should be defined,
# however using port 0 will dynamically assign a port and is recommended for roaming nodes.
listen:
  # To listen on both any ipv4 and ipv6 use "::"
  host: 0.0.0.0
  port: 4242
  # Sets the max number of packets to pull from the kernel for each syscall (under systems that support recvmmsg)
  # default is 64, does not support reload
  #batch: 64
  # Configure socket buffers for the udp side (outside), leave unset to use the system defaults. Values will be doubled by the kernel
  # Default is net.core.rmem_default and net.core.wmem_default (/proc/sys/net/core/rmem_default and /proc/sys/net/core/rmem_default)
  # Maximum is limited by memory in the system, SO_RCVBUFFORCE and SO_SNDBUFFORCE is used to avoid having to raise the system wide
  # max, net.core.rmem_max and net.core.wmem_max
  #read_buffer: 10485760
  #write_buffer: 10485760
  # By default, Nebula replies to packets it has no tunnel for with a "recv_error" packet. This packet helps speed up reconnection
  # in the case that Nebula on either side did not shut down cleanly. This response can be abused as a way to discover if Nebula is running
  # on a host though. This option lets you configure if you want to send "recv_error" packets always, never, or only to private network remotes.
  # valid values: always, never, private
  # This setting is reloadable.
  #send_recv_error: always

# Routines is the number of thread pairs to run that consume from the tun and UDP queues.
# Currently, this defaults to 1 which means we have 1 tun queue reader and 1
# UDP queue reader. Setting this above one will set IFF_MULTI_QUEUE on the tun
# device and SO_REUSEPORT on the UDP socket to allow multiple queues.
# This option is only supported on Linux.
#routines: 1

punchy:
  # Continues to punch inbound/outbound at a regular interval to avoid expiration of firewall nat mappings
  punch: true

  # respond means that a node you are trying to reach will connect back out to you if your hole punching fails
  # this is extremely useful if one node is behind a difficult nat, such as a symmetric NAT
  # Default is false
  #respond: true

  # delays a punch response for misbehaving NATs, default is 1 second.
  #delay: 1s

  # set the delay before attempting punchy.respond. Default is 5 seconds. respond must be true to take effect.
  #respond_delay: 5s

# Cipher allows you to choose between the available ciphers for your network. Options are chachapoly or aes
# IMPORTANT: this value must be identical on ALL NODES/LIGHTHOUSES. We do not/will not support use of different ciphers simultaneously!
#cipher: aes

# Preferred ranges is used to define a hint about the local network ranges, which speeds up discovering the fastest
# path to a network adjacent nebula node.
# This setting is reloadable.
#preferred_ranges: ["172.16.0.0/24"]

# sshd can expose informational and administrative functions via ssh. This can expose informational and administrative
# functions, and allows manual tweaking of various network settings when debugging or testing.
#sshd:
  # Toggles the feature
  #enabled: true
  # Host and port to listen on, port 22 is not allowed for your safety
  #listen: 127.0.0.1:2222
  # A file containing the ssh host private key to use
  # A decent way to generate one: ssh-keygen -t ed25519 -f ssh_host_ed25519_key -N "" < /dev/null
  #host_key: ./ssh_host_ed25519_key
  # Authorized users and their public keys
  #authorized_users:
    #- user: steeeeve
      # keys can be an array of strings or single string
      #keys:
        #- "ssh public key string"
  # Trusted SSH CA public keys. These are the public keys of the CAs that are allowed to sign SSH keys for access.
  #trusted_cas:
    #- "ssh public key string"

# EXPERIMENTAL: relay support for networks that can't establish direct connections.
relay:
  # Relays are a list of Nebula IP's that peers can use to relay packets to me.
  # IPs in this list must have am_relay set to true in their configs, otherwise
  # they will reject relay requests.
  #relays:
    #- 192.168.100.1
    #- <other Nebula VPN IPs of hosts used as relays to access me>
  # Set am_relay to true to permit other hosts to list my IP in their relays config. Default false.
  am_relay: false
  # Set use_relays to false to prevent this instance from attempting to establish connections through relays.
  # default true
  use_relays: true

# Configure the private interface. Note: addr is baked into the nebula certificate
tun:
  # When tun is disabled, a lighthouse can be started without a local tun interface (and therefore without root)
  disabled: false
  # Name of the device. If not set, a default will be chosen by the OS.
  # For macOS: if set, must be in the form `utun[0-9]+`.
  # For NetBSD: Required to be set, must be in the form `tun[0-9]+`
  dev: nebula1
  # Toggles forwarding of local broadcast packets, the address of which depends on the ip/mask encoded in pki.cert
  drop_local_broadcast: false
  # Toggles forwarding of multicast packets
  drop_multicast: false
  # Sets the transmit queue length, if you notice lots of transmit drops on the tun it may help to raise this number. Default is 500
  tx_queue: 500
  # Default MTU for every packet, safe setting is (and the default) 1300 for internet based traffic
  mtu: 1300

  # Route based MTU overrides, you have known vpn ip paths that can support larger MTUs you can increase/decrease them here
  routes:
    #- mtu: 8800
    #  route: 10.0.0.0/16

  # Unsafe routes allows you to route traffic over nebula to non-nebula nodes
  # Unsafe routes should be avoided unless you have hosts/services that cannot run nebula
  # NOTE: The nebula certificate of the "via" node *MUST* have the "route" defined as a subnet in its certificate
  # `mtu`: will default to tun mtu if this option is not specified
  # `metric`: will default to 0 if this option is not specified
  # `install`: will default to true, controls whether this route is installed in the systems routing table.
  # This setting is reloadable.
  unsafe_routes:
    #- route: 172.16.1.0/24
    #  via: 192.168.100.99
    #  mtu: 1300
    #  metric: 100
    #  install: true

  # On linux only, set to true to manage unsafe routes directly on the system route table with gateway routes instead of
  # in nebula configuration files. Default false, not reloadable.
  #use_system_route_table: false

# TODO
# Configure logging level
logging:
  # panic, fatal, error, warning, info, or debug. Default is info and is reloadable.
  #NOTE: Debug mode can log remotely controlled/untrusted data which can quickly fill a disk in some
  # scenarios. Debug logging is also CPU intensive and will decrease performance overall.
  # Only enable debug logging while actively investigating an issue.
  level: info
  # json or text formats currently available. Default is text
  format: text
  # Disable timestamp logging. useful when output is redirected to logging system that already adds timestamps. Default is false
  #disable_timestamp: true
  # timestamp format is specified in Go time format, see:
  #     https://golang.org/pkg/time/#pkg-constants
  # default when `format: json`: "2006-01-02T15:04:05Z07:00" (RFC3339)
  # default when `format: text`:
  #     when TTY attached: seconds since beginning of execution
  #     otherwise: "2006-01-02T15:04:05Z07:00" (RFC3339)
  # As an example, to log as RFC3339 with millisecond precision, set to:
  #timestamp_format: "2006-01-02T15:04:05.000Z07:00"

#stats:
  #type: graphite
  #prefix: nebula
  #protocol: tcp
  #host: 127.0.0.1:9999
  #interval: 10s

  #type: prometheus
  #listen: 127.0.0.1:8080
  #path: /metrics
  #namespace: prometheusns
  #subsystem: nebula
  #interval: 10s

  # enables counter metrics for meta packets
  #   e.g.: `messages.tx.handshake`
  # NOTE: `message.{tx,rx}.recv_error` is always emitted
  #message_metrics: false

  # enables detailed counter metrics for lighthouse packets
  #   e.g.: `lighthouse.rx.HostQuery`
  #lighthouse_metrics: false

# Handshake Manager Settings
#handshakes:
  # Handshakes are sent to all known addresses at each interval with a linear backoff,
  # Wait try_interval after the 1st attempt, 2 * try_interval after the 2nd, etc, until the handshake is older than timeout
  # A 100ms interval with the default 10 retries will give a handshake 5.5 seconds to resolve before timing out
  #try_interval: 100ms
  #retries: 20

  # query_buffer is the size of the buffer channel for querying lighthouses
  #query_buffer: 64

  # trigger_buffer is the size of the buffer channel for quickly sending handshakes
  # after receiving the response for lighthouse queries
  #trigger_buffer: 64


# Nebula security group configuration
firewall:
  # Action to take when a packet is not allowed by the firewall rules.
  # Can be one of:
  #   `drop` (default): silently drop the packet.
  #   `reject`: send a reject reply.
  #     - For TCP, this will be a RST "Connection Reset" packet.
  #     - For other protocols, this will be an ICMP port unreachable packet.
  outbound_action: drop
  inbound_action: drop

  # Controls the default value for local_cidr. Default is true, will be deprecated after v1.9 and defaulted to false.
  # This setting only affects nebula hosts with subnets encoded in their certificate. A nebula host acting as an
  # unsafe router with `default_local_cidr_any: true` will expose their unsafe routes to every inbound rule regardless
  # of the actual destination for the packet. Setting this to false requires each inbound rule to contain a `local_cidr`
  # if the intention is to allow traffic to flow to an unsafe route.
  #default_local_cidr_any: false

  conntrack:
    tcp_timeout: 12m
    udp_timeout: 3m
    default_timeout: 10m

  # The firewall is default deny. There is no way to write a deny rule.
  # Rules are comprised of a protocol, port, and one or more of host, group, or CIDR
  # Logical evaluation is roughly: port AND proto AND (ca_sha OR ca_name) AND (host OR group OR groups OR cidr) AND (local cidr)
  # - port: Takes `0` or `any` as any, a single number `80`, a range `200-901`, or `fragment` to match second and further fragments of fragmented packets (since there is no port available).
  #   code: same as port but makes more sense when talking about ICMP, TODO: this is not currently implemented in a way that works, use `any`
  #   proto: `any`, `tcp`, `udp`, or `icmp`
  #   host: `any` or a literal hostname, ie `test-host`
  #   group: `any` or a literal group name, ie `default-group`
  #   groups: Same as group but accepts a list of values. Multiple values are AND'd together and a certificate would have to contain all groups to pass
  #   cidr: a remote CIDR, `0.0.0.0/0` is any.
  #   local_cidr: a local CIDR, `0.0.0.0/0` is any. This could be used to filter destinations when using unsafe_routes.
  #      Default is `any` unless the certificate contains subnets and then the default is the ip issued in the certificate
  #      if `default_local_cidr_any` is false, otherwise its `any`.
  #   ca_name: An issuing CA name
  #   ca_sha: An issuing CA shasum

  outbound:
    # Allow all outbound traffic from this node
    - port: any
      proto: any
      host: any

  inbound:
    # Allow icmp between any nebula hosts
    - port: any
      proto: icmp
      host: any

    # Allow tcp/443 from any host with BOTH laptop and home group
    - port: 443
      proto: tcp
      groups:
        - laptop
        - home

    # Expose a subnet (unsafe route) to hosts with the group remote_client
    # This example assume you have a subnet of 192.168.100.1/24 or larger encoded in the certificate
    - port: 8080
      proto: tcp
      group: remote_client
      local_cidr: 192.168.100.1/24

Lighthouse config.yml

pki:
  ca: /etc/nebula/ca.crt
  cert: /etc/nebula/host.crt
  key: /etc/nebula/host.key

static_host_map:

lighthouse:
  am_lighthouse: true
  interval: 60

listen:
  host: 0.0.0.0
  port: 4242

punchy:
  punch: true

cipher: aes

relay:
  #relays:
    #- 192.168.100.1
    #- <other Nebula VPN IPs of hosts used as relays to access me>
  am_relay: true
  use_relays: true

tun:
  disabled: false
  dev: nebula1
  drop_local_broadcast: false
  drop_multicast: false
  tx_queue: 500
  mtu: 1300

logging:
  level: info
  format: text

firewall:
  outbound_action: drop
  inbound_action: drop

  conntrack:
    tcp_timeout: 12m
    udp_timeout: 3m
    default_timeout: 10m

  outbound:
    - port: any
      proto: any
      host: any

  inbound:
    - port: any
      proto: icmp
      host: any

Hosts config.yml

pki:
  ca: /etc/nebula/ca.crt
  cert: /etc/nebula/host.crt
  key: /etc/nebula/host.key

static_host_map:
  '192.168.100.1': ['api.your.run:4242']

lighthouse:
  am_lighthouse: false
  interval: 60
  hosts:
    - "192.168.100.1"

listen:
  # To listen on both any ipv4 and ipv6 use "::"
  host: 0.0.0.0
  port: 0

punchy:
  punch: true

cipher: aes

relay:
  am_relay: false
  use_relays: true

tun:
  disabled: false
  dev: nebula1
  drop_local_broadcast: false
  drop_multicast: false
  tx_queue: 500
  mtu: 1300

logging:
  level: info
  format: text

firewall:
  outbound_action: drop
  inbound_action: drop

  conntrack:
    tcp_timeout: 12m
    udp_timeout: 3m
    default_timeout: 10m

  outbound:
    - port: any
      proto: any
      host: any

  inbound:
    - port: any
      proto: icmp
      host: any

    # 일부 서버에서 HTTPS 호스팅을 위해 필요.
    - port: 443
      proto: tcp
      host: any

    # kubectl 에서 사용하는 6443 포트
    - port: 6443
      proto: tcp
      host: any

Troubleshooting

특정 Node의 서비스 재시작 이후 접속 안됨

다음과 같을 때:

  • NodeA - 현재 내 로컬 PC
  • NodeB - 서버 PC

NodeB 의 설정을 변경한 후 서비스 재시작 했는데 NodeA 에서 NodeB 로 ping 이 갑자기 안간다면... NodeA 도 재시작 해라!!!!! UDP 라서 연결 지향이 안되는게 원인일 것으로 추정함. <- 확인 필요. 어쨋든 관련 노드 전부 서비스 재시작 해라.

See also

Favorite site