add bird deploy

add data
add certs
This commit is contained in:
xiuting.xu
2026-04-23 15:13:50 +08:00
parent b60d579a38
commit cef9495534
39 changed files with 594 additions and 64 deletions

View File

@@ -1,10 +1,53 @@
FROM debian:bookworm-slim AS builder
ARG BIRD_VERSION=3.2.1
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential \
bison \
flex \
m4 \
perl \
ca-certificates \
wget \
xz-utils \
libreadline-dev \
libncurses-dev \
libssh-dev \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /build
RUN wget -O bird.tar.gz "https://bird.nic.cz/download/bird-${BIRD_VERSION}.tar.gz" \
&& tar -xzf bird.tar.gz \
&& mv "bird-${BIRD_VERSION}" bird
WORKDIR /build/bird
RUN ./configure \
--prefix=/usr \
--sysconfdir=/etc/bird \
--localstatedir=/run \
&& make -j"$(nproc)" \
&& make install
FROM debian:bookworm-slim
RUN apt-get update \
&& apt-get install -y --no-install-recommends bird2 ca-certificates \
&& rm -rf /var/lib/apt/lists/*
RUN apt-get update && apt-get install -y --no-install-recommends \
ca-certificates \
netcat-openbsd \
libreadline8 \
libncurses6 \
libtinfo6 \
libssh-4 \
&& rm -rf /var/lib/apt/lists/*
COPY --from=builder /usr/sbin/bird /usr/sbin/bird
COPY --from=builder /usr/sbin/birdc /usr/sbin/birdc
COPY --from=builder /etc/bird /etc/bird
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
RUN chmod +x /entrypoint.sh \
&& mkdir -p /run/bird
ENTRYPOINT ["/entrypoint.sh"]

View File

@@ -5,19 +5,19 @@ against this repository's RTR server defaults.
Server defaults in this repo:
- TCP: `0.0.0.0:323`
- TLS: `0.0.0.0:324`
- SSH: `0.0.0.0:22` (when enabled on server)
## Files
- `Dockerfile`: builds a minimal BIRD2 runtime image.
- `bird.conf.example`: sample `/etc/bird/bird.conf`.
- `bird.conf.tls.example`: sample TLS/mTLS `/etc/bird/bird.conf`.
- `bird.conf.ssh.example`: sample SSH transport `/etc/bird/bird.conf`.
- `entrypoint.sh`: starts BIRD in foreground mode.
- `docker-compose.yml`: one-click local TCP test client.
- `docker-compose.tls.yml`: compose override for TLS/mTLS.
- `docker-compose.ssh.yml`: compose override for SSH transport.
By default, the container prints periodic RPKI protocol snapshots to logs
every 5 seconds.
every 30 seconds.
## Docker quick start
@@ -48,12 +48,20 @@ Stop:
docker compose -f deploy/bird/docker-compose.yml down
```
## TLS/mTLS quick start
## SSH quick start
Start server in SSH mode first:
```bash
docker compose -f deploy/server/docker-compose.ssh.yml up -d --build
```
Start BIRD client with SSH override:
```bash
docker compose \
-f deploy/bird/docker-compose.yml \
-f deploy/bird/docker-compose.tls.yml \
-f deploy/bird/docker-compose.ssh.yml \
up --build
```
@@ -65,11 +73,14 @@ docker logs -f bird-rpki-client
## Notes
- This setup targets RTR over TCP (`remote "127.0.0.1" port 323`).
- This setup targets RTR over TCP (`remote "host.docker.internal" port 323`).
- `network_mode: host` expects your RTR server to be reachable at
`127.0.0.1:323` from the Docker host.
- TLS override mounts `../../certs` into `/etc/bird/certs`.
`host.docker.internal:323` from the container.
- Observation is controlled by env vars:
`OBSERVE_INTERVAL` (seconds, default `5`) and `OBSERVE_PROTO`.
`OBSERVE_INTERVAL` (seconds, default `30`) and `OBSERVE_PROTO`.
- SSH mode mounts `../../certs` into `/config/ssh` and expects:
`bird-rtr-client.pem` and `ssh_host_rsa_key.pub`.
- Entrypoint auto-generates `/run/bird/known_hosts` from
`/config/ssh/ssh_host_rsa_key.pub` for BIRD SSH host-key verification.
- If your environment does not support Docker host networking, switch to a
bridge network and replace `remote` addresses accordingly.

View File

@@ -1,21 +1,21 @@
# BIRD 最小化 RTR 客户端配置
本目录提供一个最小化 BIRD 配置,用于和本仓库 RTR Server 做黑盒互通测试。
本目录提供最小化 BIRD 配置,用于与本仓库 RTR Server 做黑盒互通测试。
本仓库默认 RTR 监听地址:
- TCP: `0.0.0.0:323`
- TLS: `0.0.0.0:324`
- SSH: `0.0.0.0:22`(仅在 server SSH 模式启用时)
## 文件说明
- `Dockerfile`: 构建最小 BIRD2 运行镜像。
- `Dockerfile`: 构建最小 BIRD 运行镜像(包含 SSH transport 支持)。
- `bird.conf.example`: `/etc/bird/bird.conf` 的 TCP 示例。
- `bird.conf.tls.example`: `/etc/bird/bird.conf` 的 TLS/mTLS 示例。
- `entrypoint.sh`: 前台启动 BIRD。
- `bird.conf.ssh.example`: `/etc/bird/bird.conf` 的 SSH transport 示例。
- `entrypoint.sh`: 前台启动 BIRD,并周期输出协议快照。
- `docker-compose.yml`: TCP 一键启动。
- `docker-compose.tls.yml`: TLS/mTLS 覆盖文件。
- `docker-compose.ssh.yml`: SSH 覆盖配置。
容器默认每 5 秒向日志输出一次 RPKI 协议状态快照。
容器默认每 30 秒向日志输出一次 RPKI 协议状态快照。
## Docker 快速启动(TCP)
@@ -25,7 +25,7 @@
docker compose -f deploy/bird/docker-compose.yml up --build
```
另开一个终端查看日志:
另开终端查看日志:
```bash
docker logs -f bird-rpki-client
@@ -46,18 +46,35 @@ docker logs -f bird-rpki-client
docker compose -f deploy/bird/docker-compose.yml down
```
## TLS/mTLS 快速启动
## SSH 快速启动
先启动 server 的 SSH 模式:
```bash
docker compose -f deploy/server/docker-compose.ssh.yml up -d --build
```
再启动 BIRD SSH 客户端:
```bash
docker compose \
-f deploy/bird/docker-compose.yml \
-f deploy/bird/docker-compose.tls.yml \
-f deploy/bird/docker-compose.ssh.yml \
up --build
```
查看日志:
```bash
docker logs -f bird-rpki-client
```
## 说明
- 当前 compose 使用 `network_mode: host`,要求容器可通过 `127.0.0.1` 访问宿主机 RTR Server。
- TLS 覆盖文件会把 `../../certs` 挂载到容器内 `/etc/bird/certs`。
- 观测频率由环境变量控制:`OBSERVE_INTERVAL`(秒,默认 `5`)和 `OBSERVE_PROTO`。
- 若你运行在 Docker Desktop(非 Linux 原生 host network 场景),建议改为自定义 bridge 网络并把 `remote` 地址改成可达的 server 容器名或宿主地址。
- 当前 compose 使用 `network_mode: host`,默认通过 `host.docker.internal` 访问 server。
- 观测频率由环境变量控制:`OBSERVE_INTERVAL`(秒,默认 `30`)和 `OBSERVE_PROTO`。
- SSH 模式会将 `../../certs` 挂载到容器 `/config/ssh`,并使用:
`bird-rtr-client.pem`、`ssh_host_rsa_key.pub`。
- 入口脚本会基于 `/config/ssh/ssh_host_rsa_key.pub` 自动生成
`/run/bird/known_hosts`,用于 BIRD 的 SSH 主机密钥校验。
- 如果你运行在 Docker Desktop(非 Linux 原生 host network 场景),建议改为自定义 bridge 网络并将 `remote` 地址改成可达的 server 容器名或宿主机地址。

View File

@@ -0,0 +1,31 @@
log stderr all;
router id 192.0.2.2;
roa4 table rtr_roa_v4;
roa6 table rtr_roa_v6;
aspa table rtr_aspa;
protocol device {
}
protocol rpki rpki_ssh {
roa4 { table rtr_roa_v4; };
roa6 { table rtr_roa_v6; };
aspa { table rtr_aspa; };
remote "host.docker.internal" port 22;
min version 2;
max version 2;
refresh 3600;
retry 600;
expire 7200;
transport ssh {
user "rpki-rtr";
bird private key "/config/ssh/rtr-client.key";
remote public key "/run/bird/known_hosts";
subsystem "rpki-rtr";
};
}

28
deploy/bird/bird.conf Normal file
View File

@@ -0,0 +1,28 @@
log stderr all;
router id 192.0.2.2;
roa4 table rtr_roa_v4;
roa6 table rtr_roa_v6;
aspa table rtr_aspa;
protocol device {
}
protocol rpki rpki_tcp {
roa4 { table rtr_roa_v4; };
roa6 { table rtr_roa_v6; };
aspa { table rtr_aspa; };
remote "host.docker.internal" port 323;
min version 2;
max version 2;
refresh 3600;
retry 600;
expire 7200;
transport tcp {
authentication none;
};
}

View File

@@ -3,6 +3,7 @@ router id 192.0.2.2;
roa4 table rtr_roa_v4;
roa6 table rtr_roa_v6;
aspa table rtr_aspa;
protocol device {
}
@@ -10,6 +11,18 @@ protocol device {
protocol rpki rpki_tcp {
roa4 { table rtr_roa_v4; };
roa6 { table rtr_roa_v6; };
aspa { table rtr_aspa; };
remote "127.0.0.1" port 323;
}
remote "host.docker.internal" port 323;
min version 2;
max version 2;
refresh 3600;
retry 600;
expire 7200;
transport tcp {
authentication none;
};
}

View File

@@ -0,0 +1,30 @@
log stderr all;
router id 192.0.2.2;
roa4 table rtr_roa_v4;
roa6 table rtr_roa_v6;
aspa table rtr_aspa;
protocol device {
}
protocol rpki rpki_ssh {
roa4 { table rtr_roa_v4; };
roa6 { table rtr_roa_v6; };
aspa { table rtr_aspa; };
remote "host.docker.internal" port 22;
min version 2;
max version 2;
refresh 3600;
retry 600;
expire 7200;
transport ssh {
user "rpki-rtr";
bird private key "/config/ssh/bird-rtr-client.pem";
remote public key "/run/bird/known_hosts";
};
}

View File

@@ -1,21 +0,0 @@
log stderr all;
router id 192.0.2.2;
roa4 table rtr_roa_v4;
roa6 table rtr_roa_v6;
protocol device {
}
protocol rpki rpki_tls {
roa4 { table rtr_roa_v4; };
roa6 { table rtr_roa_v6; };
remote "127.0.0.1" port 324;
transport tls {
ca file "/etc/bird/certs/client-ca.crt";
cert file "/etc/bird/certs/client-good.crt";
key file "/etc/bird/certs/client-good.key";
};
}

View File

@@ -0,0 +1,9 @@
services:
bird-rpki-client:
environment:
RPKI_HOST: "host.docker.internal"
RPKI_PORT: "${RPKI_RTR_SSH_PORT:-22}"
OBSERVE_PROTO: "rpki_ssh"
volumes:
- ./bird.conf.ssh.example:/config/bird.conf:ro
- ../../certs:/config/ssh:ro

View File

@@ -1,7 +0,0 @@
services:
bird-rpki-client:
environment:
OBSERVE_PROTO: rpki_tls
volumes:
- ./bird.conf.tls.example:/etc/bird/bird.conf:ro
- ../../certs:/etc/bird/certs:ro

View File

@@ -3,11 +3,30 @@ services:
build:
context: .
dockerfile: Dockerfile
args:
BIRD_VERSION: "3.2.1"
container_name: bird-rpki-client
restart: unless-stopped
network_mode: host
environment:
OBSERVE_INTERVAL: "5"
OBSERVE_PROTO: rpki_tcp
BIRD_CONFIG_PATH: "/config/bird.conf"
RPKI_HOST: "host.docker.internal"
RPKI_PORT: "323"
OBSERVE_PROTO: "rpki_tcp"
OBSERVE_INTERVAL: "30"
OBSERVE_ASPA_TABLE: "rtr_aspa"
OBSERVE_ROA4_TABLE: "rtr_roa_v4"
OBSERVE_ROA6_TABLE: "rtr_roa_v6"
OBSERVE_ASPA_COUNT: "3"
OBSERVE_ROA4_COUNT: "3"
OBSERVE_ROA6_COUNT: "3"
SHOW_ASPA: "1"
SHOW_ROA4: "1"
SHOW_ROA6: "1"
volumes:
- ./bird.conf.example:/etc/bird/bird.conf:ro
- ./bird.conf:/config/bird.conf:ro

View File

@@ -5,9 +5,122 @@ mkdir -p /run/bird
SOCK_PATH="/run/bird/bird.ctl"
PROTO="${OBSERVE_PROTO:-rpki_tcp}"
INTERVAL="${OBSERVE_INTERVAL:-5}"
INTERVAL="${OBSERVE_INTERVAL:-30}"
RPKI_HOST="${RPKI_HOST:-host.docker.internal}"
RPKI_PORT="${RPKI_PORT:-323}"
bird -f -c /etc/bird/bird.conf -s "$SOCK_PATH" &
BIRD_CONFIG_PATH="${BIRD_CONFIG_PATH:-/config/bird.conf}"
ASPA_TABLE="${OBSERVE_ASPA_TABLE:-rtr_aspa}"
ROA4_TABLE="${OBSERVE_ROA4_TABLE:-rtr_roa_v4}"
ROA6_TABLE="${OBSERVE_ROA6_TABLE:-rtr_roa_v6}"
ASPA_COUNT="${OBSERVE_ASPA_COUNT:-3}"
ROA4_COUNT="${OBSERVE_ROA4_COUNT:-3}"
ROA6_COUNT="${OBSERVE_ROA6_COUNT:-3}"
SHOW_ASPA="${SHOW_ASPA:-1}"
SHOW_ROA4="${SHOW_ROA4:-1}"
SHOW_ROA6="${SHOW_ROA6:-1}"
SSH_HOST_PUBKEY_PATH="${SSH_HOST_PUBKEY_PATH:-/config/ssh/ssh_host_rsa_key.pub}"
SSH_KNOWN_HOSTS_PATH="${SSH_KNOWN_HOSTS_PATH:-/run/bird/known_hosts}"
ensure_ssh_known_hosts() {
if [ -s "$SSH_KNOWN_HOSTS_PATH" ]; then
return
fi
if [ ! -r "$SSH_HOST_PUBKEY_PATH" ]; then
echo "[entrypoint] WARNING: SSH host key file not found: $SSH_HOST_PUBKEY_PATH"
return
fi
set -- $(awk 'NF >= 2 { print $1, $2; exit }' "$SSH_HOST_PUBKEY_PATH")
if [ $# -ne 2 ]; then
echo "[entrypoint] WARNING: invalid SSH host key format in $SSH_HOST_PUBKEY_PATH"
return
fi
key_type="$1"
key_data="$2"
if echo "$key_type" | grep -q '^ssh-'; then
{
echo "$RPKI_HOST $key_type $key_data"
echo "[$RPKI_HOST]:$RPKI_PORT $key_type $key_data"
} > "$SSH_KNOWN_HOSTS_PATH"
else
cp "$SSH_HOST_PUBKEY_PATH" "$SSH_KNOWN_HOSTS_PATH"
fi
chmod 600 "$SSH_KNOWN_HOSTS_PATH" || true
echo "[entrypoint] generated known_hosts: $SSH_KNOWN_HOSTS_PATH"
}
print_first_n_objects() {
table_name="$1"
max_objects="$2"
birdc -s "$SOCK_PATH" show route table "$table_name" all 2>/dev/null | awk -v max="$max_objects" '
BEGIN {
count = 0
}
# 直接跳过空行
/^[[:space:]]*$/ {
next
}
# 保留 birdc 的表头
/^BIRD / {
print
next
}
/^Table / {
print
next
}
# 非缩进且不是表头,视为一个新对象的开始
/^[^[:space:]]/ {
count++
if (count > max) {
exit
}
print
next
}
# 缩进内容,只有在已进入前 max 个对象时才打印
{
if (count > 0 && count <= max) {
print
}
}
' || true
}
echo "[entrypoint] starting bird"
echo "[entrypoint] config : $BIRD_CONFIG_PATH"
echo "[entrypoint] observe proto : $PROTO"
echo "[entrypoint] observe interval : $INTERVAL"
echo "[entrypoint] target : $RPKI_HOST:$RPKI_PORT"
echo "[entrypoint] show aspa : $SHOW_ASPA ($ASPA_TABLE, first $ASPA_COUNT objects)"
echo "[entrypoint] show roa4 : $SHOW_ROA4 ($ROA4_TABLE, first $ROA4_COUNT objects)"
echo "[entrypoint] show roa6 : $SHOW_ROA6 ($ROA6_TABLE, first $ROA6_COUNT objects)"
if [ "$PROTO" = "rpki_ssh" ] || grep -q 'transport[[:space:]]\+ssh' "$BIRD_CONFIG_PATH"; then
ensure_ssh_known_hosts
fi
if nc -zvw3 "$RPKI_HOST" "$RPKI_PORT"; then
echo "[entrypoint] TCP connectivity to $RPKI_HOST:$RPKI_PORT OK"
else
echo "[entrypoint] WARNING: cannot connect to $RPKI_HOST:$RPKI_PORT before BIRD starts"
fi
bird -f -c "$BIRD_CONFIG_PATH" -s "$SOCK_PATH" &
BIRD_PID="$!"
sleep 1
@@ -22,7 +135,22 @@ if [ "$INTERVAL" -gt 0 ]; then
while kill -0 "$BIRD_PID" 2>/dev/null; do
echo "==== $(date -u +"%Y-%m-%dT%H:%M:%SZ") RPKI snapshot ($PROTO) ===="
birdc -s "$SOCK_PATH" show protocols all "$PROTO" || true
birdc -s "$SOCK_PATH" show roa count || true
if [ "$SHOW_ASPA" = "1" ]; then
echo "---- ASPA table ($ASPA_TABLE, first ${ASPA_COUNT} objects) ----"
print_first_n_objects "$ASPA_TABLE" "$ASPA_COUNT"
fi
if [ "$SHOW_ROA4" = "1" ]; then
echo "---- ROA4 table ($ROA4_TABLE, first ${ROA4_COUNT} objects) ----"
print_first_n_objects "$ROA4_TABLE" "$ROA4_COUNT"
fi
if [ "$SHOW_ROA6" = "1" ]; then
echo "---- ROA6 table ($ROA6_TABLE, first ${ROA6_COUNT} objects) ----"
print_first_n_objects "$ROA6_TABLE" "$ROA6_COUNT"
fi
sleep "$INTERVAL"
done
fi