環境變數¶
ShadowDNS 可在 shadowdns.yaml 的字串值中展開 process environment variable。如此便能以同一份設定範本描述多個部署環境,同時把選定的 runtime 值留在檔案之外。
環境變數展開適合用於 listen address 等依部署而異的值;若用於機密,目標欄位必須是正常情況下不會被記錄的欄位。主要的 Secret 使用情境是 ephemeral_api.token。
Warning
不要把機密注入可能出現在一般維運日誌、驗證訊息、metrics 或產生輸出中的欄位。環境變數展開會避免 configuration-load error 洩漏值,但成功載入後不提供全域遮罩。機密只能用於 ephemeral_api.token 等正常情況下不會記錄的欄位。
Process environment¶
先在 ShadowDNS process environment 中設定變數,再從 value-side YAML 字串引用:
export API_HOST='192.0.2.10'
export API_PORT='8053'
export API_ALLOW='192.0.2.0/24'
export API_TOKEN='synthetic-secret'
go run ./cmd/shadowdns \
--config ./shadowdns.yaml \
--dry-run
# shadowdns.yaml
ephemeral_api:
listen: "${API_HOST}:${API_PORT}"
allow:
- "${API_ALLOW}"
token: "${API_TOKEN}"
aliases:
example.com:
members:
- "${BACKUP_DOMAIN:-backup.example.net}"
${NAME} 要求變數具有非空值;變數未設定或為空時,設定載入會失敗。${NAME:-default} 則在變數未設定或為空時使用 literal default。展開只會由左至右執行一次:environment value 或 default 所帶入的文字不會再次展開。
字串必須在 braced text 前保留 literal dollar sign 時,請使用 $$。例如,$${API_TOKEN} 載入後是 literal ${API_TOKEN}。完整 grammar、validation behavior 與 diagnostics contract 請見 shadowdns.yaml。
Note
展開讀取的是 ShadowDNS process environment,而不是編輯設定檔之 shell 的 environment。ShadowDNS 在 systemd、container runtime 或 Kubernetes 下執行時,請在該 service 或 workload specification 中定義變數。
Kubernetes:Secret → Pod environment → ConfigMap YAML¶
把非機密的設定結構放在 ConfigMap,bearer token 則放在 Secret。Pod 將 Secret 注入 environment variable,而掛載的 shadowdns.yaml 再引用該變數。
1. 將 token 存入 Secret¶
範例使用 stringData,因為 Kubernetes 會在建立 Secret 時進行編碼。產生的 Secret 並不會只因 base64 編碼而成為加密資料;實際 cluster 應啟用 encryption at rest 並限制 RBAC 存取。
apiVersion: v1
kind: Secret
metadata:
name: shadowdns-runtime
namespace: dns-example
stringData:
ephemeral-api-token: "synthetic-secret"
2. 將設定範本存入 ConfigMap¶
只有 ephemeral_api.token 來自 Secret,其餘皆為一般、非機密設定。
apiVersion: v1
kind: ConfigMap
metadata:
name: shadowdns-config
namespace: dns-example
data:
shadowdns.yaml: |
aliases:
example.com:
members:
- backup.example.net
ephemeral_api:
listen: "192.0.2.10:8053"
allow:
- "192.0.2.0/24"
token: "${API_TOKEN}"
3. 注入 Secret 並掛載 ConfigMap¶
Container 透過 secretKeyRef 取得 API_TOKEN,ConfigMap 則掛載成 unified configuration file。
apiVersion: apps/v1
kind: Deployment
metadata:
name: shadowdns
namespace: dns-example
spec:
replicas: 1
selector:
matchLabels:
app: shadowdns
template:
metadata:
labels:
app: shadowdns
spec:
containers:
- name: shadowdns
image: registry.example.org/shadowdns:0.1.0
args:
- "--config"
- "/etc/shadowdns/shadowdns.yaml"
env:
- name: API_TOKEN
valueFrom:
secretKeyRef:
name: shadowdns-runtime
key: ephemeral-api-token
volumeMounts:
- name: config
mountPath: /etc/shadowdns
readOnly: true
volumes:
- name: config
configMap:
name: shadowdns-config
Process 啟動時,Kubernetes 會依 Secret 建立 container environment。ShadowDNS 接著讀取 /etc/shadowdns/shadowdns.yaml,並從該 process environment 解析 ${API_TOKEN}。若 Secret key 不存在或解析成空值,required expression 會使啟動 fail closed。
更新 Kubernetes Secret¶
更新 Secret 不會改變已在執行之 container 的 environment。SIGHUP 會要求 ShadowDNS reload 設定,但 process 仍只看得到舊的 API_TOKEN;因此,單獨發送 SIGHUP 不會刷新 env-backed Secret。
變更 Secret 後,請重啟 Pod,讓 Kubernetes 建立新的 process environment:
kubectl -n dns-example rollout restart deployment/shadowdns
kubectl -n dns-example rollout status deployment/shadowdns
以 volume 掛載的 ConfigMap 可在 Kubernetes projection timing 的限制下獨立更新;然而,任何透過 Pod environment variable 提供的設定值仍需重啟 Pod。Token rotation 應規劃成 rollout,而不是只執行 SIGHUP reload。
安全檢查清單¶
- 機密只放在
ephemeral_api.token等正常情況下不會記錄的欄位。 - Secret 與 ConfigMap 分開管理;不要把 token value 複製進
shadowdns.yaml。 - 限制 Kubernetes Secret 的 RBAC 存取,並啟用 Secret encryption at rest。
- Required secret 使用
${NAME},使遺漏或空值能 fail closed。 - 更新 env-backed Secret 後重啟 Pod;不要依賴 SIGHUP 刷新 process environment。
- 共享範例與 diagnostics 只使用 synthetic value、RFC 保留 domain 與 address。