1.0.0 Release IaaS
This commit is contained in:
107
docs/archives/2025-12/06_network/06_01_net_vm.md
Normal file
107
docs/archives/2025-12/06_network/06_01_net_vm.md
Normal file
@@ -0,0 +1,107 @@
|
||||
Tags: #os, #configuration, #network, #virtualization
|
||||
|
||||
## Preparation
|
||||
|
||||
### Create VM template
|
||||
|
||||
- ~/data/config/scripts/net.sh
|
||||
|
||||
```bash
|
||||
virt-install \
|
||||
--boot uefi \
|
||||
--name net \
|
||||
--os-variant debian13 \
|
||||
--vcpus 1 \
|
||||
--memory 2048 \
|
||||
--location /var/lib/libvirt/images/debian-13.0.0-amd64-netinst.iso \ # For serial installing, use `--location` instead of `--cdrom`
|
||||
--disk pool=vm-images,size=34,format=qcow2,discard=unmap \
|
||||
--network network=ovs-lan-net,portgroup=vlan10-access,model=virtio,mac=0A:49:6E:4D:01:00 \ # Use designated ovs port group
|
||||
--graphics none \
|
||||
--console pty,target_type=serial \
|
||||
--extra-args "console=ttyS0,115200"
|
||||
# After enter this command, then the console starts automatically
|
||||
# Remove all annotation before you make the sh file.
|
||||
```
|
||||
|
||||
### Debian installation
|
||||
|
||||
- Following [here](../03_common/03_01_debian_configuration.md) to install Debian.
|
||||
- Debian installer supports serial mode regardless getty@ttyS0 service is enabled or not.
|
||||
- Following [here](../03_common/03_02_iptables.md) to set iptables.
|
||||
- Following [here](../03_common/03_04_crowdsec.md) to set CrowdSec
|
||||
|
||||
#### Serial console setting
|
||||
|
||||
After installation, use `ctrl + ]` to exit console. Before setting getty@ttyS0, you can't use serial console to access VM. Therefore, use IP address set on installation, and connect net server via ssh first, following the step to enable the getty.
|
||||
|
||||
### Modify VM template settings
|
||||
|
||||
After getty setting, shutdown net vm with `shutdown` in VM or `sudo virsh shutdown net` in hypervisor to turn off vm first.
|
||||
|
||||
```bash
|
||||
virsh edit net
|
||||
```
|
||||
|
||||
```xml
|
||||
<!-- net -->
|
||||
...
|
||||
</vcpu>
|
||||
<cputune>
|
||||
<shares>512</shares>
|
||||
</cputune>
|
||||
<!-- cpu priority - 1024: default/2048: high/512: low -->
|
||||
|
||||
<!--
|
||||
<disk type='file' device='cdrom'>
|
||||
...
|
||||
</disk>
|
||||
# Remove booting disk
|
||||
-->
|
||||
```
|
||||
|
||||
```bash
|
||||
virsh dumpxml net > ~/data/config/vms/dumps/net.xml
|
||||
# Start net server with console
|
||||
```
|
||||
|
||||
### Common setting
|
||||
|
||||
- net.service
|
||||
|
||||
```ini
|
||||
# ~/data/config/services/net.service
|
||||
# ~/.config/systemd/user/net.service
|
||||
[Unit]
|
||||
Description=net Auto Booting
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
Requires=opnsense.service
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
|
||||
# Maintain status as active
|
||||
RemainAfterExit=yes
|
||||
|
||||
# CrowdSec should be set
|
||||
ExecStartPre=%h/data/config/scripts/wait-for-it.sh 192.168.10.1:8080 -t 0
|
||||
|
||||
ExecStartPre=/bin/bash -c "sleep 15"
|
||||
|
||||
# Run the service
|
||||
ExecStart=/usr/bin/virsh -c qemu:///system start net
|
||||
|
||||
# Stop the service
|
||||
ExecStop=/usr/bin/virsh -c qemu:///system shutdown net
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
||||
```
|
||||
|
||||
```bash
|
||||
ln -s ~/data/config/services/net.service ~/.config/systemd/user/net.service
|
||||
|
||||
systemctl --user daemon-reload
|
||||
systemctl --user enable net.service
|
||||
systemctl --user start net.service
|
||||
```
|
||||
387
docs/archives/2025-12/06_network/06_02_net_ddns.md
Normal file
387
docs/archives/2025-12/06_network/06_02_net_ddns.md
Normal file
@@ -0,0 +1,387 @@
|
||||
Tags: #os, #configuration, #network
|
||||
|
||||
## DDNS
|
||||
|
||||
### Secret management
|
||||
|
||||
- File:
|
||||
- ~/data/config/secrets/.secret.yaml
|
||||
- /etc/secrets/2001/ddns.env
|
||||
|
||||
- Edit `.secret.yaml` with `edit_secret.sh`
|
||||
|
||||
```yaml
|
||||
# ~/data/config/secrets/.secret.yaml
|
||||
# DDNS
|
||||
DDNS:
|
||||
ZONE_ID: 'encrypted value'
|
||||
API_KEY: 'encrypted value'
|
||||
```
|
||||
|
||||
```bash
|
||||
extract_secret.sh ~/data/config/secrets/.secret.yaml -e "DDNS" > /run/user/$UID/tmp.env && sudo mv /run/user/$UID/tmp.env /etc/secrets/$UID/ddns.env && sudo chown $UID:root /etc/secrets/$UID/ddns.env && sudo chmod 400 /etc/secrets/$UID/ddns.env
|
||||
```
|
||||
|
||||
### ddns.sh
|
||||
|
||||
- File: ~/data/config/scripts/ddns/ddns.sh
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# ~/data/config/scripts/ddns.sh
|
||||
|
||||
# Designate directory
|
||||
# DIRECTORY="$HOME/data/config/scripts"
|
||||
|
||||
# Information
|
||||
DOMAIN=""
|
||||
TTL=180
|
||||
C_TTL=86400
|
||||
PROXIED="false"
|
||||
DELETE_FLAG="false"
|
||||
CURRENT_IP=""
|
||||
|
||||
# These will be injected by systemd
|
||||
# ZONE_ID='.secret'
|
||||
# API_KEY='.secret'
|
||||
|
||||
# usage() function
|
||||
usage() {
|
||||
echo "Usage: $0 -d \"domain\" [-t \"ttl\"] [-p] [-r] [-c]"
|
||||
echo "-d <domain>: Specify the domain to update"
|
||||
echo "-t <ttl>: Specify the TTL(Time to live)"
|
||||
echo "-p: Specify the cloudflare proxy to use"
|
||||
echo "-r: Delete the DNS record"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# getopts to get arguments
|
||||
while getopts "d:t:pr" opt; do
|
||||
case $opt in
|
||||
d)
|
||||
DOMAIN="$OPTARG"
|
||||
;;
|
||||
t)
|
||||
TTL="$OPTARG"
|
||||
;;
|
||||
p)
|
||||
PROXIED="true"
|
||||
;;
|
||||
r)
|
||||
DELETE_FLAG="true"
|
||||
;;
|
||||
\?) # unknown options
|
||||
echo "Invalid option: -$OPTARG" >&2
|
||||
usage
|
||||
;;
|
||||
:) # parameter required option
|
||||
echo "Option -$OPTARG requires an argument." >&2
|
||||
usage
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Get option and move to parameters - This has no functional thing, because it only use arguments with parameters
|
||||
shift $((OPTIND - 1))
|
||||
|
||||
# Check necessary options
|
||||
if [ -z "$DOMAIN" ]; then
|
||||
echo "Error: -d option is required" >&2
|
||||
usage
|
||||
fi
|
||||
|
||||
if ! [[ "$TTL" =~ ^[0-9]+$ ]] || [ "$TTL" -le 0 ]; then
|
||||
echo "Error: -t option (ttl) requires a number above 0." >&2
|
||||
usage
|
||||
fi
|
||||
|
||||
# log() function
|
||||
log()
|
||||
{
|
||||
local text="$1"
|
||||
echo -e "$(date "+%Y-%m-%d %H:%M:%S"): [ddns] $text"
|
||||
}
|
||||
|
||||
# Make log directory
|
||||
# if [ ! -d "$DIRECTORY/log" ]; then
|
||||
# mkdir "$DIRECTORY/log"
|
||||
# fi
|
||||
|
||||
# Check and create log file
|
||||
# LOG_FILE="$DIRECTORY/log/ddns_$(date "+%Y-%m-%d").log"
|
||||
# if [ ! -f "$LOG_FILE" ]; then
|
||||
# log "Notice: log file is created"
|
||||
# fi
|
||||
|
||||
# Check package
|
||||
if ! command -v curl &> /dev/null; then
|
||||
log "Error: curl package is needed"
|
||||
exit
|
||||
fi
|
||||
if ! command -v jq &> /dev/null; then
|
||||
log "Error: jq package is needed"
|
||||
exit
|
||||
fi
|
||||
|
||||
# API options
|
||||
URL="https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records"
|
||||
CONTENT_TYPE="Content-Type: application/json"
|
||||
AUTHORIZATION="Authorization: Bearer $API_KEY"
|
||||
|
||||
# Current IP check
|
||||
CURRENT_IP=$(curl -sf "https://ifconfig.me") ||\
|
||||
CURRENT_IP=$(curl -sf "https://ifconfig.kr") ||\
|
||||
CURRENT_IP=$(curl -sf "https://api.ipify.org")
|
||||
if [ "$CURRENT_IP" == "" ]; then
|
||||
log "Error: Can't get an IP"
|
||||
exit
|
||||
fi
|
||||
|
||||
# DNS functions
|
||||
|
||||
# get_dns_record() function
|
||||
get_dns_record()
|
||||
{
|
||||
local type="$1"
|
||||
local name="$2"
|
||||
|
||||
local response="$(
|
||||
curl -s "$URL?type=$type&name=$name"\
|
||||
-H "$CONTENT_TYPE"\
|
||||
-H "$AUTHORIZATION")"
|
||||
if [ "$(echo "$response" | jq -r '.success')" == "false" ]; then
|
||||
log "Error: Can't get dns record\"Reason: $response"
|
||||
exit
|
||||
else
|
||||
echo "$response"
|
||||
fi
|
||||
}
|
||||
|
||||
# create_dns_record() function
|
||||
create_dns_record()
|
||||
{
|
||||
local type="$1"
|
||||
local name="$2"
|
||||
local ttl="$3"
|
||||
local comment="$4"
|
||||
local content="$5"
|
||||
local response="$(
|
||||
curl -s "$URL"\
|
||||
-X POST\
|
||||
-H "$CONTENT_TYPE"\
|
||||
-H "$AUTHORIZATION"\
|
||||
-d "{
|
||||
\"name\": \"$name\",
|
||||
\"ttl\": $ttl,
|
||||
\"type\": \"$type\",
|
||||
\"comment\": \"$comment\",
|
||||
\"content\": \"$content\",
|
||||
\"proxied\": $PROXIED
|
||||
}")"
|
||||
if [ "$(echo "$response" | jq -r '.success')" == "false" ]; then
|
||||
log "Error: Can't create dns record\"Reason: $response"
|
||||
exit
|
||||
else
|
||||
echo "$response"
|
||||
fi
|
||||
}
|
||||
|
||||
# update_dns_record() function
|
||||
update_dns_record()
|
||||
{
|
||||
local type="$1"
|
||||
local name="$2"
|
||||
local ttl="$3"
|
||||
local comment="$4"
|
||||
local content="$5"
|
||||
local id="$6"
|
||||
local response=$(
|
||||
curl -s "$URL/$id"\
|
||||
-X PUT\
|
||||
-H "$CONTENT_TYPE"\
|
||||
-H "$AUTHORIZATION"\
|
||||
-d "{
|
||||
\"name\": \"$name\",
|
||||
\"ttl\": $ttl,
|
||||
\"type\": \"$type\",
|
||||
\"comment\": \"$comment\",
|
||||
\"content\": \"$content\",
|
||||
\"proxied\": $PROXIED
|
||||
}")
|
||||
if [ "$(echo "$response" | jq -r '.success')" == "false" ]; then
|
||||
log "Error: Can't update dns record\"Reason: $response"
|
||||
exit
|
||||
else
|
||||
echo "$response"
|
||||
fi
|
||||
}
|
||||
|
||||
# delete_dns_record() function
|
||||
delete_dns_record()
|
||||
{
|
||||
local type="$1"
|
||||
local id="$2"
|
||||
|
||||
local response=$(
|
||||
curl -s "$URL/$id"\
|
||||
-X DELETE\
|
||||
-H "$CONTENT_TYPE"\
|
||||
-H "$AUTHORIZATION"
|
||||
)
|
||||
if [ "$(echo "$response" | jq -r '.success')" == "false" ]; then
|
||||
log "Error: Can't delete dns record\"Reason: $response"
|
||||
exit
|
||||
else
|
||||
echo "$response"
|
||||
fi
|
||||
}
|
||||
|
||||
# Get DNS A, and CNAME record
|
||||
A_DNS_RECORD=$(get_dns_record "A" "$DOMAIN")
|
||||
S_DNS_RECORD=$(get_dns_record "cname" "*.$DOMAIN")
|
||||
W_DNS_RECORD=$(get_dns_record "cname" "www.$DOMAIN")
|
||||
|
||||
# Delete DNS record with Delete flag
|
||||
if [ "$DELETE_FLAG" == "true" ]; then
|
||||
FLAG="false"
|
||||
if [ "$(echo $A_DNS_RECORD | jq -r '.result | length')" -eq 1 ]; then
|
||||
A_DNS_ID="$(echo $A_DNS_RECORD | jq -r '.result[0].id')"
|
||||
delete_dns_record "A" "$A_DNS_ID"
|
||||
log "Delete: root DNS record is deleted"
|
||||
FLAG="true"
|
||||
fi
|
||||
if [ "$(echo $S_DNS_RECORD | jq -r '.result | length')" -eq 1 ]; then
|
||||
S_DNS_ID="$(echo $S_DNS_RECORD | jq -r '.result[0].id')"
|
||||
delete_dns_record "cname" "$S_DNS_ID"
|
||||
log "Delete: sub DNS record is deleted"
|
||||
FLAG="true"
|
||||
fi
|
||||
if [ "$(echo $W_DNS_RECORD | jq -r '.result | length')" -eq 1 ]; then
|
||||
W_DNS_ID="$(echo $W_DNS_RECORD | jq -r '.result[0].id')"
|
||||
delete_dns_record "cname" "$W_DNS_ID"
|
||||
log "Delete: www DNS record is deleted"
|
||||
FLAG="true"
|
||||
fi
|
||||
if [ "$FLAG" == "false" ]; then
|
||||
log "Notice: Nothing is Deleted. There are no DNS records"
|
||||
fi
|
||||
exit
|
||||
fi
|
||||
|
||||
# Create or update DNS A record
|
||||
if [ "$(echo $A_DNS_RECORD | jq -r '.result | length')" -eq 1 ]; then # root DNS record exist
|
||||
A_DNS_ID="$(echo $A_DNS_RECORD | jq -r '.result[0].id')"
|
||||
A_DNS_CONTENT="$(echo $A_DNS_RECORD | jq -r '.result[0].content')"
|
||||
A_DNS_TTL="$(echo $A_DNS_RECORD | jq -r '.result[0].ttl')"
|
||||
A_DNS_PROXIED="$(echo $A_DNS_RECORD | jq -r '.result[0].proxied')"
|
||||
if [ "$A_DNS_CONTENT" != $CURRENT_IP -o "$A_DNS_TTL" != "$TTL" -o "$A_DNS_PROXIED" != "$PROXIED" ]; then
|
||||
update_dns_record "A" "$DOMAIN" "$TTL" "$(date "+%Y-%m-%d %H:%M:%S"): root domain from ddns.sh" "$CURRENT_IP" "$A_DNS_ID"
|
||||
log "Update: Root DNS record is successfully changed\nDomain: $DOMAIN\nIP: $A_DNS_CONTENT to $CURRENT_IP\nTTL: $A_DNS_TTL to $TTL\nproxied: $A_DNS_PROXIED to $PROXIED"
|
||||
else
|
||||
log "Notice: Root DNS record is not changed\nDomain: $DOMAIN\nIP: $CURRENT_IP\nTTL: $TTL\nproxied: $PROXIED"
|
||||
fi
|
||||
else # root DNS record does not exist
|
||||
create_dns_record "A" "$DOMAIN" "$TTL" "$(date "+%Y-%m-%d %H:%M:%S"): root domain from ddns.sh" "$CURRENT_IP"
|
||||
log "Create: Root DNS record is successfully created\nDomain: $DOMAIN\nIP: $CURRENT_IP\nTTL: $TTL\nproxied: $PROXIED"
|
||||
fi
|
||||
|
||||
# Create or update DNS CNAME records
|
||||
if [ "$(echo $S_DNS_RECORD | jq -r '.result | length')" -eq 1 ]; then # sub DNS record exist
|
||||
S_DNS_ID="$(echo $S_DNS_RECORD | jq -r '.result[0].id')"
|
||||
S_DNS_CONTENT="$(echo $S_DNS_RECORD | jq -r '.result[0].content')"
|
||||
S_DNS_TTL="$(echo $S_DNS_RECORD | jq -r '.result[0].ttl')"
|
||||
S_DNS_PROXIED="$(echo $S_DNS_RECORD | jq -r '.result[0].proxied')"
|
||||
if [ "$S_DNS_CONTENT" != "$DOMAIN" -o "$S_DNS_TTL" != "$C_TTL" -o "$S_DNS_PROXIED" != "$PROXIED" ]; then
|
||||
update_dns_record "cname" "*.$DOMAIN" "$C_TTL" "$(date "+%Y-%m-%d %H:%M:%S"): sub domain from ddns.sh" "$DOMAIN" "$S_DNS_ID"
|
||||
log "Update: Sub DNS record is successfully changed\nDomain: $S_DNS_CONTENT to *.$DOMAIN\ncname: $DOMAIN \nTTL: $S_DNS_TTL to $C_TTL\nproxied: $S_DNS_PROXIED to $PROXIED"
|
||||
else
|
||||
log "Notice: Sub DNS record is not changed\nDomain: *.$DOMAIN\ncname: $DOMAIN\nTTL: $C_TTL\nproxied: $PROXIED"
|
||||
fi
|
||||
else # sub DNS record does not exist
|
||||
create_dns_record "cname" "*.$DOMAIN" "$C_TTL" "$(date "+%Y-%m-%d %H:%M:%S"): sub domain from ddns.sh" "$DOMAIN"
|
||||
log "Create: Sub DNS record is successfully created\nDomain: *.$DOMAIN\ncname: $DOMAIN\nTTL: $C_TTL\nproxied: $PROXIED"
|
||||
fi
|
||||
|
||||
if [ "$(echo $W_DNS_RECORD | jq -r '.result | length')" -eq 1 ]; then # www DNS record exist
|
||||
W_DNS_ID="$(echo $W_DNS_RECORD | jq -r '.result[0].id')"
|
||||
W_DNS_CONTENT="$(echo $W_DNS_RECORD | jq -r '.result[0].content')"
|
||||
W_DNS_TTL="$(echo $W_DNS_RECORD | jq -r '.result[0].ttl')"
|
||||
W_DNS_PROXIED="$(echo $W_DNS_RECORD | jq -r '.result[0].proxied')"
|
||||
if [ "$W_DNS_CONTENT" != "$DOMAIN" -o "$W_DNS_TTL" != "$C_TTL" -o "$W_DNS_PROXIED" != "$PROXIED" ]; then
|
||||
update_dns_record "cname" "www.$DOMAIN" "$C_TTL" "$(date "+%Y-%m-%d %H:%M:%S"): www domain from ddns.sh" "$DOMAIN" "$W_DNS_ID"
|
||||
log "Update: www DNS record is successfully changed\nDomain: $W_DNS_CONTENT to www.$DOMAIN\ncname: $DOMAIN\nTTL: $W_DNS_TTL to $C_TTL\nproxied: $W_DNS_PROXIED to $PROXIED"
|
||||
else
|
||||
log "Notice: www DNS record is not changed\nDomain: www.$DOMAIN\ncname: $DOMAIN\nTTL: $C_TTL\nproxied: $PROXIED"
|
||||
fi
|
||||
else # www DNS record does not exist
|
||||
create_dns_record "cname" "www.$DOMAIN" "$C_TTL" "$(date "+%Y-%m-%d %H:%M:%S"): www domain from ddns.sh" "$DOMAIN"
|
||||
log "Create: www DNS record is successfully created\nDomain: www.$DOMAIN\ncname: $DOMAIN\nTTL: $C_TTL\nproxied: $PROXIED"
|
||||
fi
|
||||
|
||||
# Remove old backup file (7days before)
|
||||
# find "$DIRECTORY/log" -maxdepth 1 -type f -mtime +7 -delete
|
||||
```
|
||||
|
||||
### Systemd
|
||||
|
||||
- File:
|
||||
- ~/data/config/services/ddns/ddns.service
|
||||
- ~/data/config/services/ddns/ddns.timer
|
||||
- /etc/secrets/2001/ddns.env
|
||||
|
||||
```ini
|
||||
# ~/data/config/services/ddns/ddns.service
|
||||
# ~/.config/systemd/user/ddns.service
|
||||
[Unit]
|
||||
Description=DDNS Update Service
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
|
||||
# logging
|
||||
StandardOutput=journal
|
||||
StandardError=journal
|
||||
|
||||
# EnvironmentFile
|
||||
EnvironmentFile=/etc/secrets/%U/ddns.env
|
||||
|
||||
# Run the script
|
||||
ExecStart=/bin/bash -c '%h/data/config/scripts/ddns/ddns.sh -d "ilnmors.com"'
|
||||
|
||||
```
|
||||
|
||||
```ini
|
||||
# ~/data/config/services/ddns/ddns.timer
|
||||
# ~/.config/systemd/user/ddns.timer
|
||||
[Unit]
|
||||
Description=Run DDNS update service every 5 minutes
|
||||
|
||||
[Timer]
|
||||
# Execute service after 1 min on booting
|
||||
OnBootSec=1min
|
||||
|
||||
# Execute service every 5mins
|
||||
OnUnitActiveSec=5min
|
||||
|
||||
# When timer is activated, Service also starts.
|
||||
Persistent=true
|
||||
|
||||
[Install]
|
||||
WantedBy=timers.target
|
||||
```
|
||||
|
||||
```bash
|
||||
# Register service
|
||||
mkdir -p ~/.config/systemd/user && chmod -R 700 ~/.config
|
||||
|
||||
ln -s ~/data/config/services/ddns/ddns.service ~/.config/systemd/user/ddns.service
|
||||
|
||||
ln -s ~/data/config/services/ddns/ddns.timer ~/.config/systemd/user/ddns.timer
|
||||
|
||||
systemctl --user daemon-reload
|
||||
|
||||
# Start timer and enable
|
||||
systemctl --user enable --now ddns.timer
|
||||
```
|
||||
338
docs/archives/2025-12/06_network/06_03_net_bind.md
Normal file
338
docs/archives/2025-12/06_network/06_03_net_bind.md
Normal file
@@ -0,0 +1,338 @@
|
||||
Tags: #os, #configuration, #network, #virtualization, #container
|
||||
|
||||
## BIND9
|
||||
|
||||
BIND9 is an open source authoritative DNS software of ISC. It can work as a personal authoritative in private network environment.
|
||||
|
||||
### Secret management
|
||||
|
||||
- File:
|
||||
- ~/data/config/secrets/.secret.yaml
|
||||
|
||||
- Edit `.secret.yaml` with `edit_secret.sh`
|
||||
|
||||
#### Generate TSIG key as ACME key
|
||||
|
||||
```bash
|
||||
podman run --rm --entrypoint /bin/sh internetsystemsconsortium/bind9:9.20 -c "tsig-keygen -a hmac-sha256 acme-key"
|
||||
# Paste and add on .secret.yaml
|
||||
# key "acme-key" {
|
||||
# algorithm hmac-sha256;
|
||||
# secret "your_base64_tsig_secret_here";
|
||||
# };'
|
||||
```
|
||||
|
||||
```yaml
|
||||
# ~/data/config/secrets/.secret.yaml
|
||||
BIND9_ACME_KEY: |
|
||||
key "acme-key" {
|
||||
algorithm hmac-sha256;
|
||||
secret "your_base64_tsig_secret_here";
|
||||
};
|
||||
```
|
||||
|
||||
```bash
|
||||
# Copy the secret value from .secret.yaml
|
||||
|
||||
# Podman secret
|
||||
extract_secret.sh ~/data/config/secrets/.secret.yaml -f "BIND9_ACME_KEY" | podman secret create "acme-key" -
|
||||
```
|
||||
|
||||
|
||||
### Preparation
|
||||
|
||||
#### iptables and firewall rules
|
||||
|
||||
- Set iptables first, following [here](../03_common/03_02_iptables.md).
|
||||
- Set firewall rules first, following [here](Latest/05_firewall/05_04_opnsense_rules.md).
|
||||
|
||||
#### Create directory for container
|
||||
|
||||
```bash
|
||||
mkdir -p ~/data/containers/bind
|
||||
chmod 700 ~/data/containers/bind
|
||||
sudo setfacl -m d:g::0 ~/data/containers/bind
|
||||
sudo setfacl -m d:o::0 ~/data/containers/bind
|
||||
sudo setfacl -m u:net:rwx ~/data/containers/bind
|
||||
sudo setfacl -m u:100052:rwx ~/data/containers/bind
|
||||
sudo setfacl -d -m u:net:rwx ~/data/containers/bind
|
||||
sudo setfacl -d -m u:100052:rwx ~/data/containers/bind
|
||||
mkdir -p ~/data/containers/bind/{cache,etc,lib,log}
|
||||
nano ~/data/containers/bind/{etc,lib}/configuration_files
|
||||
```
|
||||
|
||||
> BIND9 container executes as 53:53(bind:bind) permission in container. It is mapped host's 100052. Therefore, directories have to have ACL via `setfacl`
|
||||
|
||||
|
||||
### Podman Image
|
||||
|
||||
```bash
|
||||
podman pull internetsystemsconsortium/bind9:9.20 # Do not use latest version to management
|
||||
```
|
||||
|
||||
### Configuration files
|
||||
|
||||
> If `named.conf` file didn't exist in `/etc/bind` or it had error in it, the container would be terminated without any logs. Before starting BIND container, you should makes all configuration file already.
|
||||
|
||||
#### named.conf
|
||||
|
||||
- file: ~/data/containers/bind/etc/named.conf
|
||||
|
||||
```ini
|
||||
include "/run/secrets/keys/acme-key";
|
||||
include "/run/secrets/keys/ddns-key";
|
||||
|
||||
options {
|
||||
directory "/var/cache/bind";
|
||||
|
||||
listen-on { any; };
|
||||
listen-on-v6 { ::1; };
|
||||
|
||||
// Authoritative DNS setting
|
||||
allow-recursion { none; };
|
||||
allow-transfer { none; };
|
||||
allow-update { none; };
|
||||
|
||||
dnssec-validation no;
|
||||
|
||||
check-names master warn;
|
||||
};
|
||||
|
||||
zone "ilnmors.internal." {
|
||||
type primary;
|
||||
file "/var/lib/bind/db.ilnmors.internal";
|
||||
notify yes;
|
||||
// ACME-01 challenge policy. It allows only subdomain's TXT record update.
|
||||
update-policy {
|
||||
grant acme-key subdomain ilnmors.internal. TXT;
|
||||
grant ddns-key subdomain ilnmors.internal. A AAAA DHCID;
|
||||
};
|
||||
};
|
||||
|
||||
zone "1.168.192.in-addr.arpa" {
|
||||
type primary;
|
||||
file "/var/lib/bind/db.1.168.192.in-addr.arpa";
|
||||
notify yes;
|
||||
update-policy {
|
||||
grant ddns-key subdomain 1.168.192.in-addr.arpa PTR DHCID;
|
||||
};
|
||||
};
|
||||
|
||||
zone "10.168.192.in-addr.arpa" {
|
||||
type primary;
|
||||
file "/var/lib/bind/db.10.168.192.in-addr.arpa";
|
||||
notify yes;
|
||||
update-policy {
|
||||
grant ddns-key subdomain 10.168.192.in-addr.arpa PTR DHCID;
|
||||
};
|
||||
};
|
||||
|
||||
zone "ilnmors.com." {
|
||||
//split horizon dns
|
||||
type primary;
|
||||
file "/var/lib/bind/db.ilnmors.com";
|
||||
notify yes;
|
||||
};
|
||||
|
||||
logging {
|
||||
channel default_log {
|
||||
stderr;
|
||||
severity info;
|
||||
};
|
||||
category default { default_log; };
|
||||
category config { default_log; };
|
||||
category queries { default_log; };
|
||||
};
|
||||
```
|
||||
|
||||
>If ddns function were required, generate tsig key for ddns and give update policy for each zone like below.
|
||||
>
|
||||
> - include "/etc/bind/ddns-key";
|
||||
> - update-policy { grant ddns-key subdomain \[zone_domain\] ANY A AAAA TXT; };
|
||||
|
||||
- Verify the named.conf with the command `named-checkconf`
|
||||
|
||||
#### Zone files
|
||||
|
||||
> When you add the record, you should use `.` at the end of the domain. i.e. mydomain.internal.
|
||||
|
||||
- file:
|
||||
- ~/data/containers/bind/lib/db.ilnmors.internal
|
||||
|
||||
```ini
|
||||
$TTL 86400
|
||||
|
||||
@ IN SOA bind.ilnmors.internal. mail.ilnmors.internal. (
|
||||
2025113001 ; serial
|
||||
3600 ; refresh (1 hour)
|
||||
1800 ; retry (30 minutes)
|
||||
604800 ; expire (1 week)
|
||||
86400 ; minimum (1 day)
|
||||
)
|
||||
IN NS bind.ilnmors.internal.
|
||||
bind IN A 192.168.10.11
|
||||
opnsense IN A 192.168.10.1
|
||||
vmm IN A 192.168.10.10
|
||||
net IN A 192.168.10.11
|
||||
crowdsec IN CNAME opnsense.ilnmors.internal.
|
||||
adguard IN CNAME net.ilnmors.internal.
|
||||
step-ca IN CNAME auth.ilnmors.internal.
|
||||
caddy IN CNAME auth.ilnmors.internal.
|
||||
ldap IN CNAME auth.ilnmors.internal.
|
||||
authelia IN CNAME auth.ilnmors.internal.
|
||||
code-server IN CNAME dev.ilnmors.internal.
|
||||
postgresql IN CNAME dev.ilnmors.internal.
|
||||
```
|
||||
|
||||
- ~/data/containers/bind/lib/db.1.168.192.in-addr.arpa
|
||||
|
||||
```ini
|
||||
$TTL 86400
|
||||
|
||||
@ IN SOA bind.ilnmors.internal. mail.ilnmors.internal. (
|
||||
yyyymmdd01 ; serial
|
||||
3600 ; refresh (1 hour)
|
||||
1800 ; retry (30 minutes)
|
||||
604800 ; expire (1 week)
|
||||
86400 ; minimum (1 day)
|
||||
)
|
||||
IN NS bind.ilnmors.internal.
|
||||
1 IN PTR opnsense.ilnmors.internal.
|
||||
11 IN PTR console.ilnmors.internal.
|
||||
30 IN PTR printer.ilnmors.internal.
|
||||
```
|
||||
|
||||
- ~/data/containers/bind/lib/db.10.168.192.in-addr.arpa
|
||||
|
||||
```ini
|
||||
$TTL 86400
|
||||
|
||||
@ IN SOA bind.ilnmors.internal. mail.ilnmors.internal. (
|
||||
yyyymmdd01 ; serial
|
||||
3600 ; refresh (1 hour)
|
||||
1800 ; retry (30 minutes)
|
||||
604800 ; expire (1 week)
|
||||
86400 ; minimum (1 day)
|
||||
)
|
||||
IN NS bind.ilnmors.internal.
|
||||
1 IN PTR opnsense.ilnmors.internal.
|
||||
10 IN PTR vmm.ilnmors.internal.
|
||||
11 IN PTR net.ilnmors.internal.
|
||||
12 IN PTR auth.ilnmors.internal.
|
||||
13 IN PTR dev.ilnmors.internal.
|
||||
14 IN PTR app.ilnmors.internal.
|
||||
```
|
||||
|
||||
- ~/data/containers/bind/lib/db.ilnmors.com
|
||||
|
||||
```ini
|
||||
$TTL 86400
|
||||
|
||||
@ IN SOA bind.ilnmors.internal. mail.ilnmors.internal. (
|
||||
yyyymmdd01 ; serial
|
||||
3600 ; refresh (1 hour)
|
||||
1800 ; retry (30 minutes)
|
||||
604800 ; expire (1 week)
|
||||
86400 ; minimum (1 day)
|
||||
)
|
||||
IN NS bind.ilnmors.internal.
|
||||
* IN A 192.168.10.12
|
||||
```
|
||||
|
||||
```bash
|
||||
# Adguard container has Requires=bind.service. When it restarted, then Adguard also restarted.
|
||||
systemctl --user restart bind
|
||||
```
|
||||
### Quadlet
|
||||
|
||||
- File:
|
||||
- ~/data/config/containers/bind/bind.container
|
||||
|
||||
```ini
|
||||
# ~/data/config/containers/bind/bind.container
|
||||
[Quadlet]
|
||||
DefaultDependencies=false
|
||||
|
||||
[Unit]
|
||||
Description=BIND9 DNS
|
||||
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Container]
|
||||
Image=docker.io/internetsystemsconsortium/bind9:9.20
|
||||
|
||||
ContainerName=bind
|
||||
|
||||
PublishPort=2253:53/tcp
|
||||
PublishPort=2253:53/udp
|
||||
|
||||
Volume=%h/data/containers/bind/etc:/etc/bind:rw
|
||||
Volume=%h/data/containers/bind/lib:/var/lib/bind:rw
|
||||
Volume=%h/data/containers/bind/cache:/var/cache/bind:rw
|
||||
Volume=%h/data/containers/bind/log:/var/log:rw
|
||||
|
||||
Environment="TZ=Asia/Seoul"
|
||||
Secret=acme-key,target=/run/secrets/key/acme-key
|
||||
Secret=ddns-key,target=/run/secrets/key/ddns-key
|
||||
|
||||
Label=diun.enable=true
|
||||
Label=diun.watch_repo=true
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
||||
```
|
||||
|
||||
#### Create systemd `.service` file
|
||||
|
||||
```bash
|
||||
# linger has to be activated
|
||||
mkdir -p ~/.config/containers/systemd
|
||||
|
||||
ln -s ~/data/config/containers/bind/bind.container ~/.config/containers/systemd/bind.container
|
||||
|
||||
# This command makes bind.service
|
||||
systemctl --user daemon-reload
|
||||
```
|
||||
|
||||
#### Enable and start service
|
||||
|
||||
```bash
|
||||
systemctl --user start bind.service
|
||||
```
|
||||
|
||||
|
||||
### nsupdate (RFC 2136) verification
|
||||
|
||||
```bash
|
||||
# Update query at net server
|
||||
# Before test, create temp file .bind.acme-key
|
||||
nsupdate -k /run/user/$UID/.bind.acme-key
|
||||
> server 127.0.0.1 2253
|
||||
> zone ilnmors.internal
|
||||
> update add _acme-challenge.ilnmors.internal. 60 TXT "validation-test"
|
||||
> send
|
||||
> `ctrl+c`
|
||||
|
||||
# Verify
|
||||
dig @127.0.0.1 -p 2253 _acme-challenge.ilnmors.internal. TXT
|
||||
# Print
|
||||
;; QUESTION SECTION:
|
||||
;_acme-challenge.ilnmors.internal. IN TXT
|
||||
|
||||
;; ANSWER SECTION:
|
||||
_acme-challenge.ilnmors.internal. 60 IN TXT "validation-test"
|
||||
|
||||
# Delete query at net server
|
||||
nsupdate -k /run/user/$UID/.bind.acme-key
|
||||
> server 127.0.0.1 2253
|
||||
> zone ilnmors.internal
|
||||
> update delete _acme-challenge.ilnmors.internal. 60 TXT "validation-test"
|
||||
> send
|
||||
> `ctrl+c`
|
||||
|
||||
# Verify
|
||||
dig @127.0.0.1 -p 2253 _acme-challenge.ilnmors.internal. TXT
|
||||
# Print
|
||||
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 17572
|
||||
```
|
||||
293
docs/archives/2025-12/06_network/06_04_net_adguard_home.md
Normal file
293
docs/archives/2025-12/06_network/06_04_net_adguard_home.md
Normal file
@@ -0,0 +1,293 @@
|
||||
Tags: #os, #configuration, #network, #virtualization, #container
|
||||
|
||||
## AdGuard Home
|
||||
|
||||
AdGuard Home is one of open sourced recursive DNS resolver which can block malicious domain. It supports powerful DNS query filter based on ruleset and split horizon DNS service, plus recursive query on DoH and DoT towards public or internal authoritative DNS server.
|
||||
|
||||
### Secret
|
||||
|
||||
Adgaurd Home container doesn't need any secret value.
|
||||
|
||||
### Preparation
|
||||
|
||||
#### Add new domain in BIND
|
||||
|
||||
Following [here](../06_network/06_03_net_bind.md).
|
||||
|
||||
- net server
|
||||
- file: ~/data/containers/bind/lib/db.ilnmors.internal
|
||||
|
||||
```ini
|
||||
# ...
|
||||
adguard IN CNAME net.ilnmors.internal.
|
||||
# ...
|
||||
```
|
||||
|
||||
```bash
|
||||
# Adguard container has Requires=bind.service. When it restarted, then Adguard also restarted.
|
||||
systemctl --user restart bind
|
||||
```
|
||||
#### iptables and firewall rules
|
||||
|
||||
- Set iptables first, following [here](../03_common/03_02_iptables.md).
|
||||
- Set firewall rules first, following [here](Latest/05_firewall/05_04_opnsense_rules.md).
|
||||
|
||||
#### Create directory for container
|
||||
|
||||
```bash
|
||||
mkdir -p ~/data/containers/adguard
|
||||
chmod 700 ~/data/containers/adguard
|
||||
sudo setfacl -m d:g::0 ~/data/containers/adguard
|
||||
sudo setfacl -m d:o::0 ~/data/containers/adguard
|
||||
mkdir -p ~/data/containers/adguard/{work,config,certs}
|
||||
|
||||
```
|
||||
|
||||
> AdGuard Home container executes as root permission in container. It is not necessary to give `setfacl`. Because the container's root account is mapped as host's uid.
|
||||
|
||||
### Podman Image
|
||||
|
||||
```bash
|
||||
podman pull adguard/adguardhome:v0.107.68 # Do not use latest version to management
|
||||
```
|
||||
|
||||
### Quadlet
|
||||
|
||||
- File:
|
||||
- ~/data/config/containers/adguard/adguard.container
|
||||
|
||||
```ini
|
||||
# ~/data/config/containers/adguard/adguard.container
|
||||
[Quadlet]
|
||||
DefaultDependencies=false
|
||||
|
||||
[Unit]
|
||||
Description=AdGuard Home DNS
|
||||
|
||||
After=bind.service
|
||||
Requires=bind.service
|
||||
|
||||
|
||||
[Container]
|
||||
Image=docker.io/adguard/adguardhome:v0.107.68
|
||||
|
||||
ContainerName=adguard
|
||||
|
||||
AddHost=bind.ilnmors.internal:host-gateway
|
||||
|
||||
PublishPort=2053:53/tcp
|
||||
PublishPort=2053:53/udp
|
||||
PublishPort=2443:443/tcp
|
||||
PublishPort=2443:443/udp
|
||||
PublishPort=3000:3000/tcp
|
||||
# 3000 is temporary port, After TLS setting, delete it.
|
||||
|
||||
Volume=%h/data/containers/adguard/work:/opt/adguardhome/work:rw
|
||||
Volume=%h/data/containers/adguard/config:/opt/adguardhome/conf:rw
|
||||
Volume=%h/data/containers/adguard/certs:/etc/ssl/adguard:ro
|
||||
|
||||
Environment="TZ=Asia/Seoul"
|
||||
|
||||
Label=diun.enable=true
|
||||
Label=diun.watch_repo=true
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
||||
```
|
||||
|
||||
#### Create systemd `.service` file
|
||||
|
||||
```bash
|
||||
ln -s ~/data/config/containers/adguard/adguard.container ~/.config/containers/systemd/adguard.container
|
||||
|
||||
systemctl --user daemon-reload
|
||||
```
|
||||
|
||||
#### Enable and start service
|
||||
|
||||
```bash
|
||||
systemctl --user start adguard.service
|
||||
```
|
||||
|
||||
|
||||
### Web UI configuration
|
||||
|
||||
#### Access web UI and initial setting
|
||||
|
||||
- URL: http://192.168.10.11:3000
|
||||
> After TLS certificate setting, access to adguard via https `https://192.168.10.11` or `https://adguard.ilnmors.internal`
|
||||
|
||||
#### Initial setting wizard
|
||||
|
||||
- Administrator interface
|
||||
- Network interface: all
|
||||
- Interface port: 3000
|
||||
- DNS server
|
||||
- Network interface: all
|
||||
- Interface port: 53
|
||||
- Authentication
|
||||
- User: adguard
|
||||
- Password: Password
|
||||
|
||||
### AdGuard Configuration
|
||||
|
||||
#### General setting
|
||||
|
||||
- Filter update interval: 1 hour
|
||||
- \[\*\] Use AdGuard browsing security web service
|
||||
- \[\*\] Enable log
|
||||
- Query logs rotation - 90 days
|
||||
- \[\*\] Enable statistics
|
||||
- `Save`
|
||||
|
||||
#### DNS settings
|
||||
|
||||
- Upstream DNS servers
|
||||
|
||||
```text
|
||||
# Cloudflare DNS
|
||||
tls://security.cloudflare-dns.com
|
||||
# Internal DNS bind.ilnmors.internal:2253
|
||||
[/ilnmors.internal/]udp://bind.ilnmors.internal:2253
|
||||
# Split Horizon DNS
|
||||
[/*.ilnmors.com/]udp://bind.ilnmors.internal:2253
|
||||
```
|
||||
|
||||
> Internal authoritative DNS will be BIND. BIND will use 2253 port. `bind.ilnmors.internal` is defined on container's `/etc/hosts`, it allows communication with host system.
|
||||
|
||||
- \[\*\] Parallel requests
|
||||
- Private reverse DNS servers
|
||||
|
||||
```text
|
||||
udp://bind.ilnmors.internal:2253
|
||||
```
|
||||
|
||||
> Set this option after BIND prepared
|
||||
|
||||
- \[\*\] Use private reverse DNS resolvers
|
||||
- \[\*\] Enable reverse resolving of client's IP addresses
|
||||
- `Apply` and `Test upstreams`
|
||||
|
||||
- \[ \] Enable cache
|
||||
|
||||
- `Save`
|
||||
- Disallowed domains
|
||||
|
||||
```text
|
||||
...
|
||||
wpad.ilnmors.internal
|
||||
_ldap._tcp.dc._msdcs.ilnmors.internal
|
||||
```
|
||||
|
||||
- `Save configuration`
|
||||
|
||||
#### Client settings
|
||||
|
||||
- Add Client
|
||||
|
||||
| Client | Name |
|
||||
| :----------------------------------------------: | :-------: |
|
||||
| 169.254.1.2, 192.168.10.11 | localhost |
|
||||
| 10.10.10.2, 10.10.10.3, 10.10.10.4, 192.168.1.11 | console |
|
||||
|
||||
#### Filters - DNS blocklists
|
||||
|
||||
- Add blocklist - Choose from the list
|
||||
- 1Hosts (Lite)
|
||||
- AdGuard DNS filter
|
||||
- AdAway DNS Popup Hosts filter
|
||||
- HaGeZi's Ultimate Blocklist
|
||||
- OISD Blocklist Big
|
||||
- KOR: List-KR DNS
|
||||
|
||||
#### DNS rewrites
|
||||
|
||||
- Filters:DNS rewrites
|
||||
- bind.ilnmors.internal - 192.168.10.11
|
||||
|
||||
#### Clients' DNS setting
|
||||
|
||||
##### OPNsense
|
||||
|
||||
- System:Settings:General
|
||||
- DNS server: 192.168.10.11
|
||||
- Services:KEA DHCP:KEA DHCPv4:Subnets
|
||||
- DNS server: 192.168.10.11
|
||||
|
||||
##### Hypervisor
|
||||
|
||||
- /etc/resolv.conf
|
||||
- nameserver 192.168.10.11
|
||||
|
||||
##### net
|
||||
|
||||
- /etc/resolv.conf
|
||||
- nameserver 192.168.10.11
|
||||
|
||||
##### VPN client
|
||||
```ini
|
||||
[Interface]
|
||||
DNS = 192.168.10.11
|
||||
```
|
||||
|
||||
|
||||
---
|
||||
#### Encryption setting
|
||||
|
||||
> It requires `BIND` and `Step-CA`
|
||||
|
||||
- \[\*\] Enable Encryption (HTTPS, DNS-over_HTTPS, and DNS-over-TLS)
|
||||
- \[\*\] Enable plain DNS
|
||||
- \[\*\] Redirect to HTTPS automatically
|
||||
- HTTPS port: 443
|
||||
|
||||
##### Certificates
|
||||
|
||||
> AdGuard home doesn't support ACME protocol by itself. It is necessary to use OPNsense's ACME client function to automate adguard home certificates.
|
||||
|
||||
- Add new domain in BIND, Following [here](../06_network/06_03_net_bind.md).
|
||||
- net server
|
||||
- file: ~/data/containers/bind/lib/db.ilnmors.internal
|
||||
```text
|
||||
...
|
||||
adguard IN CNAME net.ilnmors.internal.
|
||||
...
|
||||
```
|
||||
|
||||
- ACME setting (OPNsense)
|
||||
- Services:ACME Client:Certificates - Certificates - \[+\]
|
||||
- Common Name: adguard.ilnmors.internal
|
||||
- Description: adguard
|
||||
- ACME Account: acme.ilnmors.internal
|
||||
> Even though provisioner's name includes `@`, it has to use as `.`.
|
||||
>
|
||||
> i.e. `acme@ilnmors.internal` > `acme.ilnmors.internal`
|
||||
- Challenge Type: ilnmors.internal-dns-01-challenge
|
||||
- \[\*\] Auto Renewal
|
||||
- Automations: adguard-auto-acme, adguard-auto-restart
|
||||
|
||||
- Automations (OPNsense)
|
||||
- Services:ACME Client:Automations - Automation - \[+\]
|
||||
- Name: adguard-auto-acme / adguard-auto-restart
|
||||
- Description: adguard acme crt issue / restart adguard after crt is issued
|
||||
- Run Command: Upload certificate via SFTP / Remote command via SSH
|
||||
- SFTP Host: adguard.ilnmors.internal
|
||||
- Username: net
|
||||
- Identity Type: ed25519
|
||||
- Remote Path(SFTP): /home/net/data/containers/adguard/certs
|
||||
- Command(SSH): systemctl --user restart adguard
|
||||
- `Show Identity`
|
||||
> Copy Required parameters `ssh-ed25519 ~~~ root@opnsense.ilnmors.internal`
|
||||
>
|
||||
> Add parameters in net server's ~/.ssh/authorized_keys
|
||||
- `Test Connect` and `Save`
|
||||
|
||||
- \[\*\] Set a certificates file path: `/etc/ssl/adguard/adguard.ilnmors.internal/fullchain.pem`
|
||||
- \[\*\] Set a private key file: `/etc/ssl/adguard/adguard.ilnmors.internal/key.pem`
|
||||
- \[Save configuration\]
|
||||
|
||||
##### Modify container file
|
||||
|
||||
- Delete `PublishPort=3000:3000/tcp` part
|
||||
- `systemctl --user daemon-reload`
|
||||
- `systemctl --user start adguard`
|
||||
630
docs/archives/2025-12/06_network/06_05_net_kea.md
Normal file
630
docs/archives/2025-12/06_network/06_05_net_kea.md
Normal file
@@ -0,0 +1,630 @@
|
||||
Tags: #os, #configuration, #network, #virtualization, #container
|
||||
|
||||
|
||||
# KEA
|
||||
|
||||
#### Generate TSIG key as DDNS key
|
||||
|
||||
```bash
|
||||
podman run --rm --entrypoint /bin/sh internetsystemsconsortium/bind9:9.20 -c "tsig-keygen -a hmac-sha256 acme-key"
|
||||
# Paste and add on .secret.yaml
|
||||
# key "acme-key" {
|
||||
# algorithm hmac-sha256;
|
||||
# secret "your_base64_tsig_secret_here";
|
||||
# };'
|
||||
```
|
||||
|
||||
### DHCPv4
|
||||
#### Add user to group
|
||||
|
||||
```bash
|
||||
sudo apt install kea-dhcp4-server kea-dhcp-ddns-server
|
||||
sudo usermod -aG _kea net
|
||||
sudo chmod 770 /etc/kea /var/lib/kea
|
||||
sudo chmod 660 /etc/kea/kea-dhcp4.conf
|
||||
sudo mkdir /etc/secrets/$(id -u _kea)
|
||||
sudo chown _kea:root /etc/secrets/$(id -u _kea)
|
||||
sudo chmod 500 /etc/secrets/$(id -u _kea)
|
||||
sudo touch /etc/secrets/$(id -u _kea)/ddns-key
|
||||
sudo nano /etc/secrets/$(id -u _kea)/ddns-key
|
||||
sudo chown _kea:root /etc/secrets/$(id -u _kea)/ddns-key
|
||||
sudo chmod 400 /etc/secrets/$(id -u _kea)/ddns-key
|
||||
```
|
||||
|
||||
iptables
|
||||
```
|
||||
*mangle
|
||||
|
||||
*filter
|
||||
-A INPUT -p udp -m udp --dport 67 -m comment --comment "allow upd DHCPv4 connection" -j ACCEPT
|
||||
|
||||
# check
|
||||
sudo bash -c 'iptables-restore --test < /etc/iptables/rules.v4'
|
||||
```
|
||||
|
||||
kea-dhcp4.conf
|
||||
```json
|
||||
{
|
||||
"Dhcp4": {
|
||||
"subnet4": [
|
||||
{
|
||||
"subnet": "192.168.10.0/24",
|
||||
"pools" : [
|
||||
{
|
||||
"pool": "192.168.10.254-192.168.10.254"
|
||||
}
|
||||
],
|
||||
"option-data": [
|
||||
{
|
||||
"name": "routers",
|
||||
"data": "192.168.10.1"
|
||||
},
|
||||
{
|
||||
"name": "ntp-servers",
|
||||
"data": "192.168.10.1"
|
||||
},
|
||||
{
|
||||
"name": "domain-name-servers",
|
||||
"data": "192.168.10.11"
|
||||
},
|
||||
{
|
||||
"name": "domain-name",
|
||||
"data": "ilnmors.internal"
|
||||
}
|
||||
],
|
||||
"reservations": [
|
||||
{
|
||||
"hw-address": "0a:49:6e:4d:02:00",
|
||||
"ip-address": "192.168.10.12",
|
||||
"hostname": "auth"
|
||||
},
|
||||
{
|
||||
"hw-address": "0a:49:6e:4d:03:00",
|
||||
"ip-address": "192.168.10.13",
|
||||
"hostname": "dev"
|
||||
},
|
||||
{
|
||||
"hw-address": "0a:49:6e:4d:04:00",
|
||||
"ip-address": "192.168.10.14",
|
||||
"hostname": "app"
|
||||
}
|
||||
],
|
||||
"id": 1,
|
||||
"interface": "enp1s0"
|
||||
},
|
||||
{
|
||||
"subnet": "192.168.1.0/24",
|
||||
"relay": {
|
||||
"ip-addresses": [ "192.168.1.1" ]
|
||||
},
|
||||
"pools": [
|
||||
{
|
||||
"pool": "192.168.1.100-192.168.1.254"
|
||||
}
|
||||
],
|
||||
"option-data": [
|
||||
{
|
||||
"name": "routers",
|
||||
"data": "192.168.1.1"
|
||||
},
|
||||
{
|
||||
"name": "ntp-servers",
|
||||
"data": "192.168.1.1"
|
||||
},
|
||||
{
|
||||
"name": "domain-name-servers",
|
||||
"data": "192.168.10.11"
|
||||
},
|
||||
{
|
||||
"name": "domain-name",
|
||||
"data": "ilnmors.internal"
|
||||
}
|
||||
],
|
||||
"reservations": [
|
||||
{
|
||||
"hw-address": "d8:e2:df:ff:1b:d5",
|
||||
"ip-address": "192.168.1.11",
|
||||
"hostname": "surface"
|
||||
},
|
||||
{
|
||||
"hw-address": "38:ca:84:94:5e:06",
|
||||
"ip-address": "192.168.1.30",
|
||||
"hostname": "printer"
|
||||
}
|
||||
],
|
||||
"id": 2,
|
||||
"interface": "enp1s0"
|
||||
}
|
||||
],
|
||||
"interfaces-config": {
|
||||
"interfaces": [
|
||||
"enp1s0"
|
||||
],
|
||||
"dhcp-socket-type": "raw",
|
||||
"service-sockets-max-retries": 5,
|
||||
"service-sockets-require-all": true
|
||||
},
|
||||
"renew-timer": 1000,
|
||||
"rebind-timer": 2000,
|
||||
"valid-lifetime": 4000,
|
||||
"loggers": [
|
||||
{
|
||||
"name": "kea-dhcp4",
|
||||
"output_options": [
|
||||
{
|
||||
"output": "stdout"
|
||||
}
|
||||
],
|
||||
"severity": "INFO"
|
||||
}
|
||||
],
|
||||
"lease-database": {
|
||||
"type": "memfile",
|
||||
"persist": true,
|
||||
"name": "/var/lib/kea/kea-leases4.csv",
|
||||
"lfc-interval": 3600
|
||||
},
|
||||
"dhcp-ddns": {
|
||||
"enable-updates": false,
|
||||
"server-ip": "127.0.0.1",
|
||||
"server-port": 53001
|
||||
"ncr-protocol": "UDP"
|
||||
"ncr-format": "JSON"
|
||||
},
|
||||
"ddns-send-updates": true,
|
||||
"ddns-update-on-renew": true,
|
||||
"ddns-qualifying-suffix": "ilnmors.internal",
|
||||
"ddns-override-no-update": true,
|
||||
"ddns-override-client-update": true,
|
||||
"ddns-replace-client-name": "when-present",
|
||||
"ddns-generated-prefix": "host"
|
||||
"hostname-char-set": "[^a-zA-Z0-9.-]",
|
||||
"hostname-char-replacement": "-"
|
||||
}
|
||||
}
|
||||
|
||||
// There is one interface for DHCP host. In this case, the subnet which has dhcp server should be `id=1`. Because Kea DHCP allocate IP from the `id=1` subnet when it recieve pacekt has no giaddr. When Kea DHCP is running on Router, then id is not important because DHCP allocate IP based on their interface.
|
||||
```
|
||||
|
||||
#### OPNsense
|
||||
- Services:Kea DHCP:Kea DHCPv4
|
||||
- \[ \] Enabled
|
||||
- Services:DHCP Relay:Configuration
|
||||
- Destination - \[+\]
|
||||
- Name: kea-dhcp-v4
|
||||
- Server: 192.168.10.11
|
||||
- Relays - \[+\]
|
||||
- \[\*\] Enabled
|
||||
- Interface: LAN
|
||||
- Desitination kea-dhcp-v4
|
||||
- \[ \]Agent Information
|
||||
- Status `green box` check
|
||||
|
||||
### DDNS
|
||||
|
||||
```bash
|
||||
sudo nano /etc/apparmor.d/local/usr.sbin.kea-dhcp-ddns
|
||||
|
||||
# /etc/secrets/** r,
|
||||
|
||||
sudo apparmor_parser -r /etc/apparmor.d/usr.sbin.kea-dhcp-ddns
|
||||
sudo systemctl restart kea-dhcp-ddns-server.service
|
||||
```
|
||||
|
||||
/etc/secrets/102/ddns-key
|
||||
```json
|
||||
[
|
||||
{
|
||||
"name": "ddns-key",
|
||||
"algorithm": hmac-sha256;
|
||||
"secret": "secret_value"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
/etc/kea/kea-dhcp-ddns.conf
|
||||
```json
|
||||
{
|
||||
"DhcpDdns":
|
||||
{
|
||||
"ip-address": "127.0.0.1",
|
||||
"port": 53001,
|
||||
"control-socket": {
|
||||
"socket-type": "unix",
|
||||
"socket-name": "/run/kea/kea-ddns-ctrl-socket"
|
||||
},
|
||||
"tsig-keys": <?include "/etc/secrets/102/ddns-key"?>,
|
||||
"forward-ddns" : {
|
||||
"ddns-domains": [
|
||||
{
|
||||
"name": "ilnmors.internal.",
|
||||
"key-name": "ddns-key",
|
||||
"dns-servers": [
|
||||
{
|
||||
"ip-address": "127.0.0.1",
|
||||
"port": 2053
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"reverse-ddns" : {
|
||||
"ddns-domains": [
|
||||
{
|
||||
"name": "10.168.192.in-addr.arpa.",
|
||||
"key-name": "ddns-key",
|
||||
"dns-servers": [
|
||||
{
|
||||
"ip-address": "127.0.0.1",
|
||||
"port": 2053
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "1.168.192.in-addr.arpa.",
|
||||
"key-name": "ddns-key",
|
||||
"dns-servers": [
|
||||
{
|
||||
"ip-address": "127.0.0.1",
|
||||
"port": 2053
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"loggers": [
|
||||
{
|
||||
"name": "kea-dhcp-ddns",
|
||||
"output-options": [
|
||||
{
|
||||
"output": "stdout"
|
||||
}
|
||||
],
|
||||
"severity": "INFO",
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
kea-dhcp4.conf
|
||||
``` json
|
||||
// ...
|
||||
"dhcp-ddns": {
|
||||
"enable-updates": true,
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## BIND9
|
||||
|
||||
BIND9 is an open source authoritative DNS software of ISC. It can work as a personal authoritative in private network environment.
|
||||
|
||||
### Secret management
|
||||
|
||||
- File:
|
||||
- ~/data/config/secrets/.secret.yaml
|
||||
|
||||
- Edit `.secret.yaml` with `edit_secret.sh`
|
||||
|
||||
#### Generate TSIG key as ACME key
|
||||
|
||||
```bash
|
||||
podman run --rm --entrypoint /bin/sh internetsystemsconsortium/bind9:9.20 -c "tsig-keygen -a hmac-sha256 acme-key"
|
||||
# Paste and add on .secret.yaml
|
||||
# key "acme-key" {
|
||||
# algorithm hmac-sha256;
|
||||
# secret "your_base64_tsig_secret_here";
|
||||
# };'
|
||||
```
|
||||
|
||||
```yaml
|
||||
# ~/data/config/secrets/.secret.yaml
|
||||
BIND9_ACME_KEY: |
|
||||
key "acme-key" {
|
||||
algorithm hmac-sha256;
|
||||
secret "your_base64_tsig_secret_here";
|
||||
};
|
||||
```
|
||||
|
||||
```bash
|
||||
# Copy the secret value from .secret.yaml
|
||||
|
||||
# Podman secret
|
||||
extract_secret.sh ~/data/config/secrets/.secret.yaml -f "BIND9_ACME_KEY" | podman secret create "acme-key" -
|
||||
```
|
||||
|
||||
|
||||
### Preparation
|
||||
|
||||
#### iptables and firewall rules
|
||||
|
||||
- Set iptables first, following [here](../03_common/03_02_iptables.md).
|
||||
- Set firewall rules first, following [here](Latest/05_firewall/05_04_opnsense_rules.md).
|
||||
|
||||
#### Create directory for container
|
||||
|
||||
```bash
|
||||
mkdir -p ~/data/containers/bind
|
||||
chmod 700 ~/data/containers/bind
|
||||
sudo setfacl -m d:g::0 ~/data/containers/bind
|
||||
sudo setfacl -m d:o::0 ~/data/containers/bind
|
||||
sudo setfacl -m u:net:rwx ~/data/containers/bind
|
||||
sudo setfacl -m u:100052:rwx ~/data/containers/bind
|
||||
sudo setfacl -d -m u:net:rwx ~/data/containers/bind
|
||||
sudo setfacl -d -m u:100052:rwx ~/data/containers/bind
|
||||
mkdir -p ~/data/containers/bind/{cache,etc,lib,log}
|
||||
nano ~/data/containers/bind/{etc,lib}/configuration_files
|
||||
```
|
||||
|
||||
> BIND9 container executes as 53:53(bind:bind) permission in container. It is mapped host's 100052. Therefore, directories have to have ACL via `setfacl`
|
||||
|
||||
|
||||
### Podman Image
|
||||
|
||||
```bash
|
||||
podman pull internetsystemsconsortium/bind9:9.20 # Do not use latest version to management
|
||||
```
|
||||
|
||||
### Configuration files
|
||||
|
||||
> If `named.conf` file didn't exist in `/etc/bind` or it had error in it, the container would be terminated without any logs. Before starting BIND container, you should makes all configuration file already.
|
||||
|
||||
#### named.conf
|
||||
|
||||
- file: ~/data/containers/bind/etc/named.conf
|
||||
|
||||
```ini
|
||||
include "/etc/bind/key/acme-key";
|
||||
|
||||
options {
|
||||
directory "/var/cache/bind";
|
||||
|
||||
listen-on { any; };
|
||||
listen-on-v6 { ::1; };
|
||||
|
||||
// Authoritative DNS setting
|
||||
allow-recursion { none; };
|
||||
allow-transfer { none; };
|
||||
allow-update { none; };
|
||||
|
||||
dnssec-validation no;
|
||||
|
||||
check-names master warn;
|
||||
};
|
||||
|
||||
zone "ilnmors.internal." {
|
||||
type primary;
|
||||
file "/var/lib/bind/db.ilnmors.internal";
|
||||
notify yes;
|
||||
// ACME-01 challenge policy. It allows only subdomain's TXT record update.
|
||||
update-policy {
|
||||
grant acme-key subdomain ilnmors.internal. TXT;
|
||||
};
|
||||
};
|
||||
|
||||
zone "1.168.192.in-addr.arpa" {
|
||||
type primary;
|
||||
file "/var/lib/bind/db.1.168.192.in-addr.arpa";
|
||||
notify yes;
|
||||
};
|
||||
|
||||
zone "10.168.192.in-addr.arpa" {
|
||||
type primary;
|
||||
file "/var/lib/bind/db.10.168.192.in-addr.arpa";
|
||||
notify yes;
|
||||
};
|
||||
|
||||
zone "ilnmors.com." {
|
||||
//split horizon dns
|
||||
type primary;
|
||||
file "/var/lib/bind/db.ilnmors.com";
|
||||
notify yes;
|
||||
};
|
||||
|
||||
logging {
|
||||
channel default_log {
|
||||
stderr;
|
||||
severity info;
|
||||
};
|
||||
category default { default_log; };
|
||||
category config { default_log; };
|
||||
category queries { default_log; };
|
||||
};
|
||||
```
|
||||
|
||||
>If ddns function were required, generate tsig key for ddns and give update policy for each zone like below.
|
||||
>
|
||||
> - include "/etc/bind/ddns-key";
|
||||
> - update-policy { grant ddns-key subdomain \[zone_domain\] ANY A AAAA TXT; };
|
||||
|
||||
- Verify the named.conf with the command `named-checkconf`
|
||||
|
||||
#### Zone files
|
||||
|
||||
> When you add the record, you should use `.` at the end of the domain. i.e. mydomain.internal.
|
||||
|
||||
- file:
|
||||
- ~/data/containers/bind/lib/db.ilnmors.internal
|
||||
|
||||
```ini
|
||||
$TTL 86400
|
||||
|
||||
@ IN SOA bind.ilnmors.internal. mail.ilnmors.internal. (
|
||||
yyyymmdd01 ; serial
|
||||
3600 ; refresh (1 hour)
|
||||
1800 ; retry (30 minutes)
|
||||
604800 ; expire (1 week)
|
||||
86400 ; minimum (1 day)
|
||||
)
|
||||
IN NS bind.ilnmors.internal.
|
||||
bind IN A 192.168.10.11
|
||||
opnsense IN A 192.168.10.1
|
||||
vmm IN A 192.168.10.10
|
||||
net IN A 192.168.10.11
|
||||
auth IN A 192.168.10.12
|
||||
dev IN A 192.168.10.13
|
||||
app IN A 192.168.10.14
|
||||
console IN A 192.168.1.11
|
||||
printer IN A 192.168.1.30
|
||||
crowdsec IN CNAME opnsense.ilnmors.internal.
|
||||
adguard IN CNAME net.ilnmors.internal.
|
||||
step-ca IN CNAME auth.ilnmors.internal.
|
||||
caddy IN CNAME auth.ilnmors.internal.
|
||||
ldap IN CNAME auth.ilnmors.internal.
|
||||
postgresql IN CNAME dev.ilnmors.internal.
|
||||
```
|
||||
|
||||
- ~/data/containers/bind/lib/db.1.168.192.in-addr.arpa
|
||||
|
||||
```ini
|
||||
$TTL 86400
|
||||
|
||||
@ IN SOA bind.ilnmors.internal. mail.ilnmors.internal. (
|
||||
yyyymmdd01 ; serial
|
||||
3600 ; refresh (1 hour)
|
||||
1800 ; retry (30 minutes)
|
||||
604800 ; expire (1 week)
|
||||
86400 ; minimum (1 day)
|
||||
)
|
||||
IN NS bind.ilnmors.internal.
|
||||
1 IN PTR opnsense.ilnmors.internal.
|
||||
11 IN PTR console.ilnmors.internal.
|
||||
30 IN PTR printer.ilnmors.internal.
|
||||
```
|
||||
|
||||
- ~/data/containers/bind/lib/db.10.168.192.in-addr.arpa
|
||||
|
||||
```ini
|
||||
$TTL 86400
|
||||
|
||||
@ IN SOA bind.ilnmors.internal. mail.ilnmors.internal. (
|
||||
yyyymmdd01 ; serial
|
||||
3600 ; refresh (1 hour)
|
||||
1800 ; retry (30 minutes)
|
||||
604800 ; expire (1 week)
|
||||
86400 ; minimum (1 day)
|
||||
)
|
||||
IN NS bind.ilnmors.internal.
|
||||
1 IN PTR opnsense.ilnmors.internal.
|
||||
10 IN PTR vmm.ilnmors.internal.
|
||||
11 IN PTR net.ilnmors.internal.
|
||||
12 IN PTR auth.ilnmors.internal.
|
||||
13 IN PTR dev.ilnmors.internal.
|
||||
14 IN PTR app.ilnmors.internal.
|
||||
```
|
||||
|
||||
- ~/data/containers/bind/lib/db.ilnmors.com
|
||||
|
||||
```ini
|
||||
$TTL 86400
|
||||
|
||||
@ IN SOA bind.ilnmors.internal. mail.ilnmors.internal. (
|
||||
yyyymmdd01 ; serial
|
||||
3600 ; refresh (1 hour)
|
||||
1800 ; retry (30 minutes)
|
||||
604800 ; expire (1 week)
|
||||
86400 ; minimum (1 day)
|
||||
)
|
||||
IN NS bind.ilnmors.internal.
|
||||
* IN A 192.168.10.12
|
||||
```
|
||||
|
||||
```bash
|
||||
# Adguard container has Requires=bind.service. When it restarted, then Adguard also restarted.
|
||||
systemctl --user restart bind
|
||||
```
|
||||
### Quadlet
|
||||
|
||||
- File:
|
||||
- ~/data/config/containers/bind/bind.container
|
||||
|
||||
```ini
|
||||
# ~/data/config/containers/bind/bind.container
|
||||
[Quadlet]
|
||||
DefaultDependencies=false
|
||||
|
||||
[Unit]
|
||||
Description=BIND9 DNS
|
||||
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Container]
|
||||
Image=docker.io/internetsystemsconsortium/bind9:9.20
|
||||
|
||||
ContainerName=bind
|
||||
|
||||
PublishPort=2253:53/tcp
|
||||
PublishPort=2253:53/udp
|
||||
|
||||
Volume=%h/data/containers/bind/etc:/etc/bind:rw
|
||||
Volume=%h/data/containers/bind/lib:/var/lib/bind:rw
|
||||
Volume=%h/data/containers/bind/cache:/var/cache/bind:rw
|
||||
Volume=%h/data/containers/bind/log:/var/log:rw
|
||||
|
||||
Environment="TZ=Asia/Seoul"
|
||||
Secret=acme-key,target=/etc/bind/key/acme-key
|
||||
|
||||
Label=diun.enable=true
|
||||
Label=diun.watch_repo=true
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
||||
```
|
||||
|
||||
#### Create systemd `.service` file
|
||||
|
||||
```bash
|
||||
# linger has to be activated
|
||||
mkdir -p ~/.config/containers/systemd
|
||||
|
||||
ln -s ~/data/config/containers/bind/bind.container ~/.config/containers/systemd/bind.container
|
||||
|
||||
# This command makes bind.service
|
||||
systemctl --user daemon-reload
|
||||
```
|
||||
|
||||
#### Enable and start service
|
||||
|
||||
```bash
|
||||
systemctl --user start bind.service
|
||||
```
|
||||
|
||||
|
||||
### nsupdate (RFC 2136) verification
|
||||
|
||||
```bash
|
||||
# Update query at net server
|
||||
# Before test, create temp file .bind.acme-key
|
||||
nsupdate -k /run/user/$UID/.bind.acme-key
|
||||
> server 127.0.0.1 2253
|
||||
> zone ilnmors.internal
|
||||
> update add _acme-challenge.ilnmors.internal. 60 TXT "validation-test"
|
||||
> send
|
||||
> `ctrl+c`
|
||||
|
||||
# Verify
|
||||
dig @127.0.0.1 -p 2253 _acme-challenge.ilnmors.internal. TXT
|
||||
# Print
|
||||
;; QUESTION SECTION:
|
||||
;_acme-challenge.ilnmors.internal. IN TXT
|
||||
|
||||
;; ANSWER SECTION:
|
||||
_acme-challenge.ilnmors.internal. 60 IN TXT "validation-test"
|
||||
|
||||
# Delete query at net server
|
||||
nsupdate -k /run/user/$UID/.bind.acme-key
|
||||
> server 127.0.0.1 2253
|
||||
> zone ilnmors.internal
|
||||
> update delete _acme-challenge.ilnmors.internal. 60 TXT "validation-test"
|
||||
> send
|
||||
> `ctrl+c`
|
||||
|
||||
# Verify
|
||||
dig @127.0.0.1 -p 2253 _acme-challenge.ilnmors.internal. TXT
|
||||
# Print
|
||||
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 17572
|
||||
```
|
||||
Reference in New Issue
Block a user