2025-03-26

bind9使用nsupdate+acme.sh申請免費憑證

1.首先要讓bind有ddns的功能,即允許外部使用key來動態更新A或TXT等record ,

先建立key:
=====================================
b=$(dnssec-keygen -a hmac-sha512 -b 512 -n USER -K /tmp foo)

cat > /etc/named/keys/update.key <<EOF
key "mykey" {
    algorithm hmac-sha512;
    secret "$(awk '/^Key/{print $2}' /tmp/$b.private)";
};
EOF
rm -f /tmp/$b.{private,key}

===把key檔路徑include進named的設定中==
include "/etc/named/keys/update.key";
=====================================
然後把domain獨立切出一個zone(範例是只允許TXT紀錄,因為只是要用來申請免費憑證):

=====================================
zone "yourdomain.com" {
    type master;
    file "/path/to/your/zone/file"; 
    update-policy {
        grant "mykey" subdomain yourdomain.com. TXT;
    };
};
==zone file,若無dns沒a紀錄沒有關係=======================

$TTL 86400
@   IN  SOA     ns.yourdomain.com. admin.yourdomain.com. (
                2023101001 ; Serial number
                3600       ; Refresh interval (one hour)
                1800       ; Retry interval (30 minutes)
                1209600    ; Expire time (two weeks)
                86400      ; Minimum TTL (one day)
)

@  IN A 1.2.3.4
* IN A 1.2.3.4
=====================================

安裝acme.sh(一般使用者即可,當然用root會更方便些):
curl https://get.acme.sh | sh -s email=my@yourdomain.com

wget -O -  https://get.acme.sh | sh -s email=my@yourdomain.com

建立帳號並決定使用哪個免費憑證服務(預設zerossl):
acme.sh  --register-account  -m myemail@yourdomain.com --server zerossl
如要用letsencrypt的話:
acme.sh --set-default-ca  --server letsencrypt
acme.sh  --register-account  -m myemail@yourdomain.com --server letsencrypt

設定讓acme.sh自動更新:
acme.sh --upgrade --auto-upgrade

開始申請憑證(此範例為申請wildcard憑證),此處的key格式要與named include的一樣就可以了:
export NSUPDATE_SERVER="dns.yourdomain.com"
export NSUPDATE_KEY="/path/to/your/update.key"
export NSUPDATE_ZONE="yourdomain.com"

~/.acme.sh/acme.sh --issue --dns dns_nsupdate -d yourdomain.com -d *.yourdomain.com --renew-hook "/path/to/install_cert.sh"

上面指令中的install_cert.sh即憑證renew成功後要執行的動作(複製憑證+重啟web):
憑證申請成功後,先手動複製憑證+重啟web(做第一次即可)
~/.acme.sh/acme.sh --install-cert -d yourdomain.com --key-file /certs/path/yourdomain.com/key.pem --fullchain-file /certs/path/yourdomain.com/fullchain.pem --reloadcmd "sudo systemctl restart nginx.service"

因為要讓一般使用者可以重新啟動web server,需加上sudoer:
#/etc/sudoers.d/acme_install_cert
username ALL=(ALL) NOPASSWD: /bin/systemctl restart nginx.service

這樣以後每60天會自動renew憑證,且會自動複製憑證並重啟web server。

其它:
安裝acme.sh時,會自動在使用者的crontab加上以下指令,固定每天檢查憑證:
51 1 * * * "/home/username/.acme.sh"/acme.sh --cron --home "/home/username/.acme.sh" > /dev/null

~/.acme.sh/account.conf 在申請憑證完後,會把一開始export的環境變數儲存在這裡,其它設定也會放在這個檔

~/.acme.sh/yourdomain.com_ecc/yourdomain.com.conf 會放一些跟這個網域有關的設定,如
Le_API=使用的憑證廠商api
Le_RenewHook=renew hook
Le_RealKeyPath=key要複製的路徑
Le_RealFullChainPath=fullchain要複製的路徑
Le_ReloadCmd=重啟指令

ref:
https://github.com/acmesh-official/acme.sh/wiki/dnsapi#7-use-nsupdate-to-automatically-issue-cert
https://github.com/acmesh-official/acme.sh/wiki/Server
https://ezbox.idv.tw/180/bind-ddns-dynamic-dns/
https://cwza.github.io/my_blog/2015/12/02/Bind9%E7%9A%84Dynamic-Dns-Update%E8%A8%AD%E5%AE%9A%E7%AD%86%E8%A8%98/
https://ithelp.ithome.com.tw/articles/10062006
https://n.sfs.tw/content/index/11984?u=
https://bugs.launchpad.net/ubuntu/+source/bind9/+bug/2015176
https://www.hobrasoft.cz/en/blog/bravenec/acme-sh-renew-hook

2024-09-13

TOMCAT設定特定目錄不得執行JSP及JSPX

如果網站允許使用者上傳檔案,通常會禁止上傳可執行檔(如jsp & jspx),

除了檢查副檔名外,也可在app的web.xml加上以下設定,讓jsp/jspx變成唯讀:

<servlet>

        <servlet-name>DefaultServlet</servlet-name>

        <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>

        <init-param>

            <param-name>readonly</param-name>

            <param-value>true</param-value>

        </init-param>

        <load-on-startup>1</load-on-startup>

    </servlet>

    <servlet-mapping>

        <servlet-name>DefaultServlet</servlet-name>

        <url-pattern>/path/to/upload/*</url-pattern>

    </servlet-mapping>


但像jspx一般也很少人會去寫,建議直接在tomcat/conf/web.xml禁用:

<servlet-mapping>

        <servlet-name>jsp</servlet-name>

        <url-pattern>*.jsp</url-pattern>

        <!--<url-pattern>*.jspx</url-pattern>-->

 </servlet-mapping>

2024-07-16

letsencrypt憑證更新後,但伺服器(nginx/apache/tomcat)不會autoreload

letsencrypt更新了憑證後,web server並不會知道憑證要重新讀取, 此時可利用letsencrypt的hooks機制,

以nginx為例,在以下路徑寫一個可執行的shell script: 
/etc/letsencrypt/renewal-hooks/deploy/01-reload-nginx 
 ============================ 
#! /bin/sh 
set -e 
nginx -t
systemctl reload nginx
============================ 

2023-09-18

Ubuntu/Linux Mint在 Macbook 13" 2014 的無線網卡/麥克風/風扇/攝影機設定

0.無線網卡:
因為broadcom的網卡driver不是開源而是專有的,所以用以下指令自動安裝(如nvidia driver也是):
sudo ubuntu-drivers autoinstall

1.修正line-in麥克風:
找到 mbp 2014 13"的機型識別碼:MacBookPro11,1

再找到 driver 為 Cirrus Logic CS4208 = mbp11

修改  /etc/modprobe.d/alsa-base.conf ,新增:
options snd-hda-intel model=mbp11

2.修正風扇不正常問題:
sudo apt install mbpfan
sudo systemctl status mbpfan

避免風扇時不時狂轉,修改/etc/mbpfan.conf:
min_fan1_speed = 2000
max_fan1_speed = 3500
...
polling_interval = 5

3.修正facetime webcam:

如果是iSight鏡頭(通常是2005~2010的macbook,如果不是請略過):
下載文章附件的AppleUSBVideoSupport,解壓縮:
https://www.linux.org/threads/installing-linux-on-an-imac.26009/
sudo apt install isight-firmware-tools
指向剛剛的AppleUSBVideoSupport檔案

安裝facetime camera firmware:
sudo apt install curl xzcat cpio git
git clone https://github.com/patjak/facetimehd-firmware.git
cd facetimehd-firmware
make
sudo make install

安裝facetime camera driver:
git clone https://github.com/patjak/bcwc_pcie.git
apt install debhelper dkms
mkdir /usr/src/facetimehd-0.1
cd bcwc_pcie
cp -r * /usr/src/facetimehd-0.1/
cd /usr/src/facetimehd-0.1/
make clean
dkms add -m facetimehd -v 0.1
dkms build -m facetimehd -v 0.1
dkms mkdsc -m facetimehd -v 0.1 --source-only
dkms mkdeb -m facetimehd -v 0.1 --source-only
cp /var/lib/dkms/facetimehd/0.1/deb/facetimehd-dkms_0.1_all.deb /root/
rm -r /var/lib/dkms/facetimehd/
dpkg -i /root/facetimehd-dkms_0.1_all.deb

ref:
https://askubuntu.com/questions/1430547/webcam-not-working-in-ubuntu-22-04-on-macbook-air
https://github.com/patjak/facetimehd/wiki/Installation#get-started-on-debian
https://github.com/linux-on-mac
https://support.apple.com/zh-tw/HT201300
https://askubuntu.com/questions/984239/no-microphone-picked-up-on-ubuntu-16-04-on-macbook-pro
https://www.kernel.org/doc/html/latest/sound/hd-audio/models.html

2023-08-28

openshift 4.8 安裝後調整

一.新增自動上 letsencrypt 功能:

這樣以後在router加個annotation ->  kubernetes.io/tls-acme : true 就會自動上letsencrypt憑證了。
參考:
https://developer.ibm.com/tutorials/secure-red-hat-openshift-routes-with-lets-encrypt/
https://github.com/tnozicka/openshift-acme/tree/master/deploy#cluster-wide
https://www.redhat.com/en/blog/dynamic-ssl-certificates-using-letsencrypt-openshift

就算不是cluster admin,也可以在自已的專案內使用,比較麻煩的就是每個專案都要佈署進去一次,這裡採的是用cluster wide的方法,必須是cluster admin才行,這樣後以每個使用者就不用自已再做一次,直接上annotation就行。

做法(使用cluster admin):
1.用cluster admin -> oc login
2.執行以下命令:

$ oc new-project acme-operator
$ oc apply -fhttps://raw.githubusercontent.com/tnozicka/openshift-acme/master/deploy/single-namespace/{role,serviceaccount,issuer-letsencrypt-live,deployment}.yaml
$ oc create rolebinding openshift-acme --role=openshift-acme --serviceaccount="$( oc project -q ):openshift-acme" --dry-run -o yaml | oc apply -f -


二.設定default sotrage class:

這樣以後佈署服務時,有掛volume的話,就不用再手動指定storage class,而會自動使用預設的storage class,否則之前都要手動改PVC的yml去指定:
$ sed -i '/spec:/a\  storageClassName: managed-nfs-storage' configs/*-persistentvolumeclaim.yaml

參考
https://www.goglides.dev/bkpandey/how-to-configure-default-storage-class-in-openshift-2oj4

$oc patch storageclass managed-nfs-storage -p '{"metadata": {"annotations": {"storageclass.kubernetes.io/is-default-class": "true"}}}'


三.掛載 image registry 的 PV (persistent volume):

預設佈署完 OCP內建的 image registry是沒有作用的,因為沒有指定PV(persistent volume)給他,這樣一些功能是無法正常使用的,譬如build config (在OCP上build image),這包含了S2I (source to image)及build from dockerfile等功能,因此要先給他一個PV才能正常運作。

參考
https://www.ibm.com/docs/zh-tw/mas-cd/continuous-delivery?topic=requirements-enabling-openshift-internal-image-registry
https://access.redhat.com/documentation/en-us/openshift_container_platform/4.3/html/registry/setting-up-and-configuring-the-registry#registry-configuring-storage-baremetal_configuring-registry-storage-baremetal
https://access.redhat.com/documentation/en-us/red_hat_openshift_container_storage/4.2/html-single/managing_openshift_container_storage/index#configuring-image-registry-to-use-openshift-container-storage_rhocs

假設要掛到某個名稱為managed-nfs-storage的storage class,因為是nfs,所以要先確認nfs server上的mount option有no_wdelay 還有 root_squash (但root_squash我沒有加就是了):

# cat /etc/exports
/mnt/data *(rw,sync,no_wdelay,root_squash,insecure,fsid=0)
# systemctl restart nfs-server

再下指令:

$ oc project openshift-image-registry

$ oc create -f <(echo '{
   "apiVersion": "v1",
   "kind": "PersistentVolumeClaim",
   "metadata": {
     "name": "image-registry-storage"
   },
   "spec": {
     "storageClassName": "managed-nfs-storage",
     "accessModes": [ "ReadWriteMany" ],
     "resources": {
       "requests": { "storage": "100Gi"
     }
   }
 }
}');

================

$ oc edit configs.imageregistry.operator.openshift.io -n openshift-image-registry

======== 手動修改 ========

spec:

    managementState: Managed

storage:

      pvc:

        claim: image-registry-storage

========================

$ oc get co image-registry

===================================================

也有把PVC先掛到暫存空間的方法,但是不建議用在production的服務上:
https://serverfault.com/questions/1082295/how-to-enable-local-image-registry-on-openshift-single-node-cluster-installation

.........
  managementState: Managed
..........
  replica: 1
...........
  storage:
    emptyDir: {}

==================

之後看要不要把image registry公開到網路上(也就是建立一個route),可以用預設的DefaultRoute或是自已手動建一個route:
https://access.redhat.com/documentation/en-us/openshift_container_platform/4.8/html/registry/securing-exposing-registry

然後讓要可以登入的使用者新增role:
https://access.redhat.com/documentation/en-us/openshift_container_platform/4.8/html/registry/accessing-the-registry#prerequisites

$ oc project openshift-image-registry
$ oc policy add-role-to-user registry-viewer <user_name>
$ oc policy add-role-to-user registry-editor <user_name>

之後登入(用docker或podman都行)

$ oc whoami -t #先取得登入token,注意不是直接打使用者密碼登入!
$ podman login image-registry.your-opensfhit.domain
Username:<username>
Password:<剛取得的 token>

四.將ingress operator的default controller改用proxy protocol (haproxy也要同時修改):

這樣的好處是pod服務內的程式不但可以從X-Forward-For抓到真實的來源IP,也可以在router下annotation做IP的白名單whitelist,真的是太方便了!

參考:
https://docs.openshift.com/container-platform/4.8/networking/ingress-operator.html#nw-ingress-controller-configuration-proxy-protocol_configuring-ingress
https://www.haproxy.com/documentation/hapee/latest/load-balancing/client-ip-preservation/enable-proxy-protocol/

指令:
$ oc -n openshift-ingress-operator edit ingresscontroller/default

找到最上層的spec (注意不要加到status去了),加入:

  spec:
    endpointPublishingStrategy:
      hostNetwork:
        protocol: PROXY
      type: HostNetwork

再到 haproxy 的機器,修改 /etc/haproxy/haproxy.cfg,在 listen 或 backend 端的80, 443的server instruction加入send-proxy,mode tcp不用動,這樣就會以proxy protocol溝通(也就是每個連線會加入proxy協定自已的特殊header):

listen ingress-router-443
  bind *:443
  mode tcp
  balance source
  server worker0 worker0.example.com:443 check inter 1s send-proxy
  server worker1 worker1.example.com:443 check inter 1s send-proxy
  server worker2 worker2.example.com:443 check inter 1s send-proxy

接下來可以佈署一個簡單的網頁服務,印出header看看有沒有X-Forwarded-For帶真實IP。

router做白名單的方法:

https://docs.openshift.com/container-platform/4.8/networking/routes/route-configuration.html#nw-route-specific-annotations_route-configuration

在要限制IP的router加入annotation(IP或網段都可以,用space隔開):
haproxy.router.openshift.io/ip_whitelist:  168.85.1.1 203.22.5.0/8

================================

另外關於佈署服務:

一、imagePullPolicy

https://docs.openshift.com/container-platform/4.8/openshift_images/managing_images/image-pull-policy.html

規則如下:

If the tag is latest, OpenShift Container Platform defaults imagePullPolicy to Always.
Otherwise, OpenShift Container Platform defaults imagePullPolicy to IfNotPresent.

但是呢,實際上並不是這麼回事,即使image的tag是latest,他還是不會自動拉新的image,還是會一直使用cache裡面的,真的很困擾,因此每次佈署時,最好手動改一下deploy檔:

$ sed -i '/\          image:/a\          imagePullPolicy: Always' configs/*-deployment.yaml

二、kompose轉換為opensfhit的佈署檔而不是k8s

kompose convert加參數--provider openshift並用 oc apply -f 佈署

https://kubernetes.io/docs/tasks/configure-pod-container/translate-compose-kubernetes/#openshift-kompose-convert-example

但實際上用會有些轉不太完整,

如image stream的設定檔*.imagestream.yaml要手動加 spec.tag.name(image的tag號,應該是bug)

不支援docker compose file的 extra_hosts 參數,得要自已在*.deploymentconfig.yaml的spec.template.spec 手動加:

hostAliases:
        - ip: "100.1.2.3"
          hostnames:
          - "myhost.domain.com"


反而不加--provider openshift參數並改用 kubectl apply -f 倒是沒啥問題...


三、讓container集中在一個pod,而不是一個container就一個pod

可以在kompose convert加參數 --multiple-container-mode 試試

https://github.com/kubernetes/kompose/pull/1394?source=post_page-----20ce5313be1e--------------------------------

四、關於pod運行時的一些權限問題

https://ithelp.ithome.com.tw/articles/10243781

由於OCP對容器的限制比k8s嚴格,不准容器內直接用root(uid= 0 或 root)去執行,而是會隨機給一個UID,但給予的GID是屬於root group的(gid= 0 或 root),因此寫dockerfile時,最好把會動到的目錄(如寫入log 或 tmp 或安裝 plugin檔等的目錄,就是有可能寫入或動到檔案的地方):

RUN chgrp -R 0 /some/directory \
  && chmod -R g+rwX /some/directory

docker compose file的service 可以加入user來指定使用者跟群組:
https://docs.docker.com/compose/compose-file/05-services/#user
如在service下面指定
user: 0:0

user: root:root
但這在 openshift 是沒用的,因為就是不允許 root 去跑...

那如果硬要使用image預設指定的user去跑呢?那就要先在專案建一個SA(service account),再把anyuid這個scc policy指定給SA,然後在專案config寫入指定SA:

#用 admin 執行 (一次就好)
oc project my-project
oc create sa my-sa
oc adm policy add-scc-to-user anyuid -z my-sa

#用 user 執行patch (每次重deploy都要)
oc patch dc gitlab -p '{"spec":{"template":{"spec":{"serviceAccountName": "gitlab-sa"}}}}'

#或手動加到deploymentconfig.yaml (每次重deploy都要)

spec:
  template:
    spec:
      serviceAccountName: my-sa

五、關於 coredns 查詢dns時的問題

用以下指令,可發現 cluster的dns ip 固定為 172.30.0.10:
oc get svc -n openshift-dns dns-default -o wide

用172.30.0.10去查,有時會出現 "truncated, retrying in tcp mode":
dig xxx.test.domain @172.30.0.10
nslookup xxx.test.domain 172.30.0.10

再根據以下二篇文章說明,可知dns查詢時,若是回傳的資訊量太大(>512),可能就會由UDP查詢變為TCP查詢,因此會出現 "truncated, retrying in tcp mode"是正常的,不是壞掉:
https://bugzilla.redhat.com/show_bug.cgi?id=2043046#c3
https://bugzilla.redhat.com/show_bug.cgi?id=2062307#c14

因此去檢查upstream的dns server時,發現 53/TCP 竟然沒監聽,只剩下 53/UDP,因此把bind給重啟就好了,只是怎麼會掛掉…蠻神奇的。

六、Ingress Controller 數量不夠的問題

參照:
https://access.redhat.com/discussions/5490621#comment-2288691
https://access.redhat.com/documentation/zh-tw/openshift_container_platform/4.5/html/networking/configuring-ingress-controller#nw-ingress-controller-configuration_configuring-ingress

單位的openshift平台配置了六個node,master x 3(作為api的管理pod用),worker x 3(作為使用者專案產生的pod運行)。


某天查haproxy的log時,發現有以下訊息:
localhost haproxy[3679]: Server ingress-router-80/worker0 is DOWN, reason: Layer4 connection problem, info: "Connection refused", check duration: 0ms. 2 active and 0 backup servers left. 0 sessions active, 0 requeued, 0 remaining in queue.

表示worker0的haproxy(也是就ingress controller)沒在跑,因此80/443都被refused,netstate去檢查80/443也沒有程式在監聽,用以下指令查目前的ingress controller的replicas數量:

$ oc get -n openshift-ingress-operator ingresscontrollers/default -o jsonpath='{$.status.availableReplicas}'

發現數量只有2,但有3台worker,數量當然不夠,因此增加replica的數量:

$ oc patch -n openshift-ingress-operator ingresscontroller/default --patch '{"spec":{"replicas": 3}}' --type=merge

設定haproxy log的方法:https://linuxconfig.org/install-and-configure-haproxy-on-redhat-8



2023-02-14

在macbook pro M1安裝Ubuntu 22.04

在macbook pro M1的UTM安裝Ubuntu arm版很簡單,照下列一步步安裝即可:
https://docs.getutm.app/guides/ubuntu/

官方的教學是安裝server版再安裝ubuntu-desktop,
若需要直接安裝有桌面的ubuntu arm版,可在下面下載:
https://cdimage.ubuntu.com/jammy/daily-live/current/

有個比較需要注意的是utm的模擬顯示卡,及x11跟wayland的問題,
在ubntu登入畫面點擊姓名,再點擊右下角的齒輪,
可選擇gdm3 session使用X11或wayland登入,但因utm的顯卡模擬有些還是有bug,
如顯卡模擬選項有gpu support的(如virtio-ramfb-gl),選擇x11或wayland登入時,可能造成某些軟體視窗打不開或一片黑,若遇到問題先不要選有gpu support的,選virtio-ramfb就好,這樣用x11就比較不會有問題(或有的用wayland沒問題,切換試試)。或更新utm看看能不能解決。

2023-02-12

RK987在Linux/Ubuntu下模擬成Apple鍵盤造成Function keys不正常的問題

 二年多前在淘寶買的RK987藍芽雙模鍵盤,在Linux/Ubuntu下的F1-F12總是會模擬成多媒體鍵(不管有無加上Fn),用lsusb指令查看,發現這鍵盤的vid:pid是05ac:024f,名稱是Apple Keyboard,才發現這鍵盤把自已假裝成Apple鍵盤了,這導致Linux會自動載入hid_apple驅動,但這鍵盤的F1-F12卻又無法正常使用。

解法是修改Fn的預設行為:

echo "options hid_apple fnmode=2" | sudo tee -a /etc/modprobe.d/hid_apple.conf 
sudo update-initramfs -u <for Ubntu/Debain>
sudo mkinitcpio -P <for Arch>

並將鍵盤模式用Fn+A切換成WIN模式。

下面解釋了Fn設為0,1,2的不同:

  1. 0 = disabled : Disable the 'fn' key. Pressing 'fn'+'F8' will behave like you only press 'F8'
  2. 1 = fkeyslast : Function keys are used as last key. Pressing 'F8' key will act as a special key. Pressing 'fn'+'F8' will behave like a F8.
  3. 2 = fkeysfirst : Function keys are used as first key. Pressing 'F8' key will behave like a F8. Pressing 'fn'+'F8' will act as special key (play/pause).

ref:
https://unix.stackexchange.com/questions/604791/keyboard-function-keys-always-trigger-media-shortcuts-regardless-of-whether-fn
https://unix.stackexchange.com/questions/121395/on-an-apple-keyboard-under-linux-how-do-i-make-the-function-keys-work-without-t
https://unix.stackexchange.com/a/672672