K8s 系列(三) - 如何配置 etcd https 證書?

在 K8s 中身隐,kube-apiserver 使用 etcd 對 REST object 資源進(jìn)行持久化存儲廷区,本文介紹如何配置生成自簽 https 證書,搭建 etcd 集群給 apiserver 使用贾铝,并附相關(guān)坑點記錄隙轻。

1. 安裝 cfssl 工具

cd /data/work

wget https://github.com/cloudflare/cfssl/releases/download/v1.6.0/cfssl_1.6.0_linux_amd64 -O cfssl
wget https://github.com/cloudflare/cfssl/releases/download/v1.6.0/cfssljson_1.6.0_linux_amd64 -O cfssljson
wget https://github.com/cloudflare/cfssl/releases/download/v1.6.0/cfssl-certinfo_1.6.0_linux_amd64 -O cfssl-certinfo

chmod +x cfssl*
mv cfssl* /usr/local/bin/


chmod +x cfssl*
mv cfssl_linux-amd64 /usr/local/bin/cfssl
mv cfssljson_linux-amd64 /usr/local/bin/cfssljson
mv cfssl-certinfo_linux-amd64 /usr/local/bin/cfssl-certinfo

2. 創(chuàng)建 ca 證書

cat > ca-csr.json <<EOF
{
  "CN": "etcd-ca",
  "key": {
      "algo": "rsa",
      "size": 2048
  },
  "names": [
    {
      "C": "CN",
      "ST": "Beijing",
      "L": "Beijing",
      "O": "etcd-ca",
      "OU": "etcd-ca"
    }
  ],
  "ca": {
          "expiry": "87600h"
  }
}
EOF


cfssl gencert -initca ca-csr.json | cfssljson -bare ca

=> 會生成:ca-key.pem, ca.csr, ca.pem

3. 配置 ca 證書策略

cat > ca-config.json <<EOF
{
  "signing": {
      "default": {
          "expiry": "87600h"
        },
      "profiles": {
          "etcd-ca": {
              "usages": [
                  "signing",
                  "key encipherment",
                  "server auth",
                  "client auth"
              ],
              "expiry": "87600h"
          }
      }
  }
}
EOF

4. 配置 etcd 請求 csr

cat > etcd-csr.json <<EOF
{
  "CN": "etcd",
  "hosts": [
    "127.0.0.1",
    "etcd0-0.etcd",
    "etcd1-0.etcd",
    "etcd2-0.etcd"
  ],
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [{
    "C": "CN",
    "ST": "Beijing",
    "L": "Beijing",
    "O": "etcd",
    "OU": "etcd"
  }]
}
EOF

5. 生成 etcd 證書

cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=etcd-ca etcd-csr.json | cfssljson  -bare etcd

=> 會生成:etcd-key.pem, etcd.csr, etcd.pem

6. 創(chuàng)建 etcd cluster

yaml 文件:https://github.com/k8s-club/etcd-operator

kubectl apply -f etcd-cluster.yaml

7. 查看 DNS 解析

dnsutils 安裝:https://kubernetes.io/docs/tasks/administer-cluster/dns-debugging-resolution/

kubectl exec -it -n etcd dnsutils -- nslookup etcd

Server:         9.165.x.x
Address:        9.165.x.x#53

Name:   etcd.etcd.svc.cluster.local
Address: 9.165.x.x
Name:   etcd.etcd.svc.cluster.local
Address: 9.165.x.x
Name:   etcd.etcd.svc.cluster.local
Address: 9.165.x.x

8. 查看 etcd 集群狀態(tài)

kubectl exec -it -n etcd etcd0-0 -- sh

/usr/local/bin/etcdctl --write-out=table --cacert=/etc/etcd/ssl/ca.pem --cert=/etc/etcd/ssl/etcd.pem --key=/etc/etcd/ssl/etcd-key.pem --endpoints=https://etcd0-0.etcd:2379,https://etcd1-0.etcd:2379,https://etcd2-0.etcd:2379 endpoint health

+---------------------------+--------+-------------+-------+
|         ENDPOINT          | HEALTH |    TOOK     | ERROR |
+---------------------------+--------+-------------+-------+
| https://etcd0-0.etcd:2379 |   true | 13.551982ms |       |
| https://etcd1-0.etcd:2379 |   true | 13.540498ms |       |
| https://etcd2-0.etcd:2379 |   true | 23.119639ms |       |
+---------------------------+--------+-------------+-------+

/usr/local/bin/etcdctl --write-out=table --cacert=/etc/etcd/ssl/ca.pem --cert=/etc/etcd/ssl/etcd.pem --key=/etc/etcd/ssl/etcd-key.pem --endpoints=https://etcd0-0.etcd:2379,https://etcd1-0.etcd:2379,https://etcd2-0.etcd:2379 endpoint status

+--------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
|         ENDPOINT         |        ID        | VERSION | DB SIZE | IS LEADER | IS LEARNER | RAFT TERM | RAFT INDEX | RAFT APPLIED INDEX | ERRORS |
+--------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
| http://etcd0-0.etcd:2379 | 4dde210279eea33a |  3.4.13 |   20 kB |      true |      false |         2 |          9 |                  9 |        |
| http://etcd1-0.etcd:2379 | 20669865d12a473b |  3.4.13 |   20 kB |     false |      false |         2 |          9 |                  9 |        |
| http://etcd2-0.etcd:2379 | 3f17922d1ed63113 |  3.4.13 |   20 kB |     false |      false |         2 |          9 |                  9 |        |
+--------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+

9. 驗證 etcd 讀寫

kubectl exec -it -n etcd etcd0-0 -- sh

/usr/local/bin/etcdctl --cacert=/etc/etcd/ssl/ca.pem --cert=/etc/etcd/ssl/etcd.pem --key=/etc/etcd/ssl/etcd-key.pem put hello world
OK

/usr/local/bin/etcdctl --cacert=/etc/etcd/ssl/ca.pem --cert=/etc/etcd/ssl/etcd.pem --key=/etc/etcd/ssl/etcd-key.pem get hello
hello
world

查看所有 keys:
/usr/local/bin/etcdctl --cacert=/etc/etcd/ssl/ca.pem --cert=/etc/etcd/ssl/etcd.pem --key=/etc/etcd/ssl/etcd-key.pem get "" --keys-only --prefix
hello

查看所有 key-val:
/usr/local/bin/etcdctl --cacert=/etc/etcd/ssl/ca.pem --cert=/etc/etcd/ssl/etcd.pem --key=/etc/etcd/ssl/etcd-key.pem get "" --prefix
hello
world

10. 配置 apiserver 請求 csr

cat > apiserver-csr.json <<EOF
{
  "CN": "apiserver",
  "hosts": [
    "*.etcd"
  ],
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [{
    "C": "CN",
    "ST": "Beijing",
    "L": "Beijing",
    "O": "apiserver",
    "OU": "apiserver"
  }]
}
EOF

11. 生成 apiserver 證書

cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=etcd-ca apiserver-csr.json | cfssljson  -bare apiserver

=> 會生成:apiserver-key.pem, apiserver.csr, apiserver.pem

12. 創(chuàng)建 extension-apiserver

apiserver.yaml:通過 ConfigMap 將生成的 *.pem 證書掛載給 apiserver 使用

containers:
  - image: xxxxx:latest
    args:
    - --etcd-servers=https://etcd0-0.etcd:2379
    - --etcd-cafile=/etc/kubernetes/certs/kube-apiserver-etcd-ca.crt
    - --etcd-certfile=/etc/kubernetes/certs/kube-apiserver-etcd-client.crt
    - --etcd-keyfile=/etc/kubernetes/certs/kube-apiserver-etcd-client.key
kubectl apply -f apiserver.yaml

13. 坑點記錄

13.1 證書 hosts 不對

log:
etcd0-0:
{"level":"warn","ts":"2021-08-19T11:55:07.755Z","caller":"embed/config_logging.go:279","msg":"rejected connection","remote-addr":"127.0.0.1:41226","server-name":"","error":"tls: first record does not look like a TLS handshake"}


etcd1-0:
{"level":"info","ts":"2021-08-19T11:54:16.830Z","caller":"embed/serve.go:191","msg":"serving client traffic securely","address":"[::]:2379"}
{"level":"info","ts":"2021-08-19T11:54:16.838Z","caller":"etcdserver/server.go:716","msg":"initialized peer connections; fast-forwarding election ticks","local-member-id":"30dd90df9a304e97","forward-ticks":18,"forward-duration":"4.5s","election-ticks":20,"election-timeout":"5s","active-remote-members":2}
{"level":"info","ts":"2021-08-19T11:54:16.867Z","caller":"membership/cluster.go:558","msg":"set initial cluster version","cluster-id":"80c7f1f6c2848777","local-member-id":"30dd90df9a304e97","cluster-version":"3.4"}
{"level":"info","ts":"2021-08-19T11:54:16.867Z","caller":"api/capability.go:76","msg":"enabled capabilities for version","cluster-version":"3.4"}


etcd2-0:
{"level":"warn","ts":"2021-08-19T11:54:17.782Z","caller":"embed/config_logging.go:270","msg":"rejected connection","remote-addr":"9.165.x.x:40180","server-name":"etcd2-0.etcd","ip-addresses":["0.0.0.0","127.0.0.1"],"dns-names":["etcd0-0.etcd","etcd1-0.etcd","etcd2-0.etcd"],"error":"tls: \"9.165.x.x\" does not match any of DNSNames [\"etcd0-0.etcd\" \"etcd1-0.etcd\" \"etcd2-0.etcd\"] (lookup etcd1-0.etcd on 9.165.x.x:53: no such host)"}

解決:重新配置正確的 hosts 域名

13.2 證書 hosts 配置坑點

"hosts": [
    "127.0.0.1",
    "etcd0-0.etcd",
    "*.etcd" // 允許 * 泛域名,但不能為空 "" 或 *
  ],

13.3 dns 設(shè)置參考

推薦設(shè)置 *.xxx.ns.svc垢揩,這樣擴(kuò)容后也不需要重簽證書

參考:https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/

Go 代碼參考如下:

func genEtcdWildcardDnsName(namespace, serviceName string) []string {
    return []string{
        fmt.Sprintf("%s.%s.%s", serviceName, namespace, "svc"),
        fmt.Sprintf("*.%s.%s.%s", serviceName, namespace, "svc"),
        fmt.Sprintf("%s.%s.%s", serviceName, namespace, DnsBase),
        fmt.Sprintf("*.%s.%s.%s", serviceName, namespace, DnsBase),
    }
}

13.4 leader/follower 已經(jīng)建立成功了玖绿,但訪問報錯

# /usr/local/bin/etcdctl put hello world
{"level":"warn","ts":"2021-08-19T12:32:11.200Z","caller":"clientv3/retry_interceptor.go:62","msg":"retrying of unary invoker failed","target":"endpoint://client-05ed1825-e70f-492a-af94-03c633d0affc/127.0.0.1:2379","attempt":0,"error":"rpc error: code = DeadlineExceeded desc = latest balancer error: all SubConns are in TransientFailure, latest connection error: connection closed"}
Error: context deadline exceeded

解決:etcdctl 需要帶證書訪問

/usr/local/bin/etcdctl --cacert=/etc/etcd/ssl/ca.pem --cert=/etc/etcd/ssl/etcd.pem --key=/etc/etcd/ssl/etcd-key.pem put hello world

13.5 http 與 https 之間不能切換

先通過 http 建立了 cluster,然后再用自簽證書 https 來建立叁巨,這樣就會報錯:

tls: first record does not look like a TLS handshake

經(jīng)過驗證:無論是從 http => https斑匪,還是從 https => http 的切換都會報這個錯,因為一旦建立 cluster 成功锋勺,則把連接的協(xié)議(http/https) 寫入到 etcd 存儲里了蚀瘸,不能再更改連接協(xié)議。

解決:如果真正遇到需要切換協(xié)議庶橱,可嘗試下面方式

  • 允許刪除數(shù)據(jù):刪除后重新建立 cluster
  • 不允許刪數(shù)據(jù):可以嘗試采用 snapshot & restore 進(jìn)行快照與恢復(fù)操作

13.6 apiserver 可直接使用第 5 步生成的 etcd 證書嗎贮勃?

經(jīng)過驗證,是可以直接使用 etcd 證書的苏章,但生產(chǎn)上不建議這樣使用衙猪。

生產(chǎn)上建議對 apiserver(或其他應(yīng)用) 單獨生成證書,可使用泛域名(*.xx.xx)布近、不同過期時間等方式靈活配置,也更有利于集群管控丝格。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末撑瞧,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子显蝌,更是在濱河造成了極大的恐慌预伺,老刑警劉巖订咸,帶你破解...
    沈念sama閱讀 216,496評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異酬诀,居然都是意外死亡脏嚷,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評論 3 392
  • 文/潘曉璐 我一進(jìn)店門瞒御,熙熙樓的掌柜王于貴愁眉苦臉地迎上來父叙,“玉大人,你說我怎么就攤上這事肴裙≈撼” “怎么了?”我有些...
    開封第一講書人閱讀 162,632評論 0 353
  • 文/不壞的土叔 我叫張陵蜻懦,是天一觀的道長甜癞。 經(jīng)常有香客問我,道長宛乃,這世上最難降的妖魔是什么悠咱? 我笑而不...
    開封第一講書人閱讀 58,180評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮征炼,結(jié)果婚禮上析既,老公的妹妹穿的比我還像新娘。我一直安慰自己柒室,他們只是感情好渡贾,可當(dāng)我...
    茶點故事閱讀 67,198評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著雄右,像睡著了一般空骚。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上擂仍,一...
    開封第一講書人閱讀 51,165評論 1 299
  • 那天囤屹,我揣著相機(jī)與錄音,去河邊找鬼逢渔。 笑死肋坚,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的肃廓。 我是一名探鬼主播智厌,決...
    沈念sama閱讀 40,052評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼盲赊!你這毒婦竟也來了铣鹏?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,910評論 0 274
  • 序言:老撾萬榮一對情侶失蹤哀蘑,失蹤者是張志新(化名)和其女友劉穎诚卸,沒想到半個月后葵第,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,324評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡合溺,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,542評論 2 332
  • 正文 我和宋清朗相戀三年卒密,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片棠赛。...
    茶點故事閱讀 39,711評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡哮奇,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出恭朗,到底是詐尸還是另有隱情屏镊,我是刑警寧澤,帶...
    沈念sama閱讀 35,424評論 5 343
  • 正文 年R本政府宣布痰腮,位于F島的核電站而芥,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏膀值。R本人自食惡果不足惜棍丐,卻給世界環(huán)境...
    茶點故事閱讀 41,017評論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望沧踏。 院中可真熱鬧歌逢,春花似錦、人聲如沸翘狱。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,668評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽潦匈。三九已至阱高,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間茬缩,已是汗流浹背赤惊。 一陣腳步聲響...
    開封第一講書人閱讀 32,823評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留凰锡,地道東北人未舟。 一個月前我還...
    沈念sama閱讀 47,722評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像掂为,于是被迫代替她去往敵國和親裕膀。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,611評論 2 353

推薦閱讀更多精彩內(nèi)容