5
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

ibmcloud: Red Hat OpenShift on IBM Cloud(ROKS)が任意のnamespaceからpull-secretの構成なしで外部レジストリ(icr.io)にアクセスできる理由

Last updated at Posted at 2022-12-02

1. そもそもこの記事を書く上でのきっかけ

IBM Cloud monitoring(Sysdig)やIBM Cloud Log Analysis(LogDNA/MEZMO)をUI上からROKSに導入するとibm-observeというnamespaceにDaemon Setが作成される。利用されるイメージは、以下の通り、icr.ioという外部レジストリーを利用している。

環境情報
[root@new-syasuda-tok1-vpc1 ~]# oc version
Client Version: 4.11.0-202210250857.p0.g142cb44.assembly.stream-142cb44
Kustomize Version: v4.5.4
Server Version: 4.11.12
Kubernetes Version: v1.24.6+5157800
[root@new-syasuda-tok1-vpc1 ~]# oc get ds -n ibm-observe
NAME           DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR   AGE
logdna-agent   2         2         2       2            2           <none>          50d
sysdig-agent   2         2         2       2            2           <none>          50d

[root@new-syasuda-tok1-vpc1 ~]# oc get pods -n ibm-observe
NAME                 READY   STATUS    RESTARTS   AGE
logdna-agent-2p6p4   1/1     Running   0          30h
logdna-agent-75pxm   1/1     Running   0          30h
sysdig-agent-b9tlg   1/1     Running   0          30h
sysdig-agent-tx6q7   1/1     Running   0          30h

[root@new-syasuda-tok1-vpc1 ~]# oc get pods logdna-agent-2p6p4 -n ibm-observe -o yaml|grep -i image
    image: icr.io/ext/logdna-agent:stable
    imagePullPolicy: Always
  imagePullSecrets:
    image: icr.io/ext/logdna-agent:stable
    imageID: icr.io/ext/logdna-agent@sha256:a52f2e44ad7db9f88cb3da9565772734449ec97c8c6182b4369d42928c3eaa23

[root@new-syasuda-tok1-vpc1 ~]# oc get pods sysdig-agent-b9tlg  -n ibm-observe -o yaml|grep -i image
    image: icr.io/ext/sysdig/agent
    imagePullPolicy: Always
  imagePullSecrets:
    image: icr.io/ext/sysdig/agent:latest
    imageID: icr.io/ext/sysdig/agent@sha256:45b10702667b33b0663dd23164fc9f928945083060c14c3dd1e4b538b9348942

一方、icr.ioはpublic registryではない。以下のように認証なしにはアクセスできない。よって、どこかに認証情報が構成されている必要がある。

[root@new-syasuda-tok1-vpc1 ~]# skopeo inspect docker://icr.io/ext/istio/examples-bookinfo-reviews-v3:1.15.0
FATA[0001] Error parsing image name "docker://icr.io/ext/istio/examples-bookinfo-reviews-v3:1.15.0": unable to retrieve auth token: invalid username/password: unauthorized: The login credentials are not valid, or your IBM Cloud account is not active.

[root@new-syasuda-tok1-vpc1 ~]# skopeo inspect docker://private.icr.io/ext/istio/examples-bookinfo-reviews-v3:1.15.0
FATA[0001] Error parsing image name "docker://private.icr.io/ext/istio/examples-bookinfo-reviews-v3:1.15.0": unable to retrieve auth token: invalid username/password: unauthorized: The login credentials are not valid, or your IBM Cloud account is not active.

しかし、以下のようにこのDaemon Setに紐づいているService Accountのpull secretsにはicr.ioに関する認証情報は含まれていない。一般的には、default namespaceに存在するall-icr-ioというsecretを該当のnamespaceにコピーして使うようにガイドされているが、他にそういうsecretがコピーされている様子もない。では、どこでicr.ioへの認証は行われているのだろうか? それとも、ibm-observeというnamespaceだけ何か特別な設定がされているのだろうか?という疑問が生じたのがこの記事を書くきっかけである。

[root@new-syasuda-tok1-vpc1 ~]# oc get ds logdna-agent -n ibm-observe -o jsonpath='{.spec.template.spec.serviceAccount}{"\n"}'
logdna-agent

[root@new-syasuda-tok1-vpc1 ~]# oc describe sa logdna-agent -n ibm-observe
Name:                logdna-agent
Namespace:           ibm-observe
Labels:              <none>
Annotations:         <none>
Image pull secrets:  logdna-agent-dockercfg-lmqwp
Mountable secrets:   logdna-agent-dockercfg-lmqwp
Tokens:              logdna-agent-token-b2qgh
Events:              <none>

[root@new-syasuda-tok1-vpc1 ~]# oc get secrets logdna-agent-dockercfg-lmqwp -n ibm-observe -o jsonpath='{.data.\.dockercfg}' | base64 -d | jq
{
  "172.21.75.245:5000": {
    "username": "serviceaccount",
    "password": "<data>",
    "email": "serviceaccount@example.org",
    "auth": "<data>"
  },
  "image-registry.openshift-image-registry.svc.cluster.local:5000": {
    "username": "serviceaccount",
    "password": "<data>",
    "email": "serviceaccount@example.org",
    "auth": "<data>"
  },
  "image-registry.openshift-image-registry.svc:5000": {
    "username": "serviceaccount",
    "password": "<data>",
    "email": "serviceaccount@example.org",
    "auth": "<data>"
  }
}
[root@new-syasuda-tok1-vpc1 ~]# oc get ds sysdig-agent -n ibm-observe -o jsonpath='{.spec.template.spec.serviceAccount}{"\n"}'
sysdig-agent

[root@new-syasuda-tok1-vpc1 ~]# oc describe sa sysdig-agent -n ibm-observe
Name:                sysdig-agent
Namespace:           ibm-observe
Labels:              <none>
Annotations:         <none>
Image pull secrets:  sysdig-agent-dockercfg-5f55h
Mountable secrets:   sysdig-agent-dockercfg-5f55h
Tokens:              sysdig-agent-token-4474r
Events:              <none>

[root@new-syasuda-tok1-vpc1 ~]# oc get secrets sysdig-agent-dockercfg-5f55h -n ibm-observe -o jsonpath='{.data.\.dockercfg}' | base64 -d | jq
{
  "172.21.75.245:5000": {
    "username": "serviceaccount",
    "password": "<data>",
    "email": "serviceaccount@example.org",
    "auth": "<data>"
  },
  "image-registry.openshift-image-registry.svc.cluster.local:5000": {
    "username": "serviceaccount",
    "password": "<data>",
    "email": "serviceaccount@example.org",
    "auth": "<data>"
  },
  "image-registry.openshift-image-registry.svc:5000": {
    "username": "serviceaccount",
    "password": "<data>",
    "email": "serviceaccount@example.org",
    "auth": "<data>"
  }
}

openshift-configなどのnamespaceにも当然含まれていない。

[root@new-syasuda-tok1-vpc1 ~]# oc get secrets -n openshift-config
NAME                       TYPE                                  DATA   AGE
builder-dockercfg-td579    kubernetes.io/dockercfg               1      510d
builder-token-wrmmf        kubernetes.io/service-account-token   4      510d
builder-token-xzrc2        kubernetes.io/service-account-token   4      510d
default-dockercfg-45r68    kubernetes.io/dockercfg               1      510d
default-token-7kv57        kubernetes.io/service-account-token   4      510d
default-token-dhczn        kubernetes.io/service-account-token   4      510d
deployer-dockercfg-t4zq2   kubernetes.io/dockercfg               1      510d
deployer-token-fz5jv       kubernetes.io/service-account-token   4      510d
deployer-token-xjglw       kubernetes.io/service-account-token   4      510d
htpasswd-secret            Opaque                                1      497d
pull-secret                kubernetes.io/dockerconfigjson        1      510d

[root@new-syasuda-tok1-vpc1 ~]# oc get secrets pull-secret -n openshift-config -o jsonpath='{.data.\.dockerconfigjson}' | base64 -d  | jq
{
  "auths": {
    "cloud.openshift.com": {
      "auth": "<data>",
      "email": "ibmocp@us.ibm.com"
    },
    "quay.io": {
      "auth": "<data>",
      "email": "ibmocp@us.ibm.com"
    },
    "registry.connect.redhat.com": {
      "auth": "<data>",
      "email": "ibmocp@us.ibm.com"
    },
    "registry.redhat.io": {
      "auth": "<data>",
      "email": "ibmocp@us.ibm.com"
    }
  }
}

2. 任意のnamespaceからもicr.io上のイメージを取得できてしまう。

試しに、新規にprojectを作成し、そこにicr.io上のイメージを指定してPodを動かそうとしてみたが、驚くべきことに、無事イメージを取得できてしまった。当然該当するデフォルトのsecretにはicr.ioに対する認証情報は含まれていない。よって、これはIBM Cloud monitoring(Sysdig)やIBM Cloud Log Analysis(LogDNA/MEZMO)だけで何か特別に行われている構成ではなく、プラットフォーム全体で有効な設定であることが想像される。

[root@new-syasuda-tok1-vpc1 ~]# oc new-project testproject1
[root@new-syasuda-tok1-vpc1 ~]# oc run samplepod1 --image=icr.io/ext/istio/examples-bookinfo-reviews-v3:1.15.0
[root@new-syasuda-tok1-vpc1 ~]# oc get pods
NAME                         READY   STATUS    RESTARTS     AGE
samplepod1                   1/1     Running   0            30s

[root@new-syasuda-tok1-vpc1 ~]# oc describe pod samplepod1
(途中略)
  Type    Reason          Age   From               Message
  ----    ------          ----  ----               -------
  Normal  Scheduled       33s   default-scheduler  Successfully assigned syasuda1/samplepod1 to 10.0.0.25 by kube-scheduler-794dfbddfd-7sgsv
  Normal  AddedInterface  31s   multus             Add eth0 [172.17.34.53/32] from k8s-pod-network
  Normal  Pulled          31s   kubelet            Container image "icr.io/ext/istio/examples-bookinfo-reviews-v3:1.15.0" already present on machine
  Normal  Created         31s   kubelet            Created container samplepod1
  Normal  Started         31s   kubelet            Started container samplepod1

[root@new-syasuda-tok1-vpc1 ~]# oc get pods samplepod1 -o jsonpath='{.spec.imagePullSecrets[*].name}{"\n"}'
default-dockercfg-lkb8m

[root@new-syasuda-tok1-vpc1 ~]# oc get secrets
NAME                       TYPE                                  DATA   AGE
builder-dockercfg-wwwpt    kubernetes.io/dockercfg               1      15m
builder-token-x4p8g        kubernetes.io/service-account-token   4      15m
default-dockercfg-lkb8m    kubernetes.io/dockercfg               1      15m
default-token-mrv6r        kubernetes.io/service-account-token   4      15m
deployer-dockercfg-nd2kh   kubernetes.io/dockercfg               1      15m
deployer-token-9vjcg       kubernetes.io/service-account-token   4      15m


[root@new-syasuda-tok1-vpc1 ~]# oc get secrets default-dockercfg-lkb8m -o jsonpath='{.data.\.dockercfg}' | base64 -d | jq
{
  "172.21.75.245:5000": {
    "username": "serviceaccount",
    "password": "<data>",
    "email": "serviceaccount@example.org",
    "auth": "<data>"
  },
  "image-registry.openshift-image-registry.svc.cluster.local:5000": {
    "username": "serviceaccount",
    "password": "<data>",
    "email": "serviceaccount@example.org",
    "auth": "<data>"
  },
  "image-registry.openshift-image-registry.svc:5000": {
    "username": "serviceaccount",
    "password": "<data>",
    "email": "serviceaccount@example.org",
    "auth": "<data>"
  }
}

ちなみに、icr.ioではなく、private.icr.ioを利用した場合は以下のように失敗するため、これはicr.ioだけ許容される操作なのであろうと想像される。

[root@new-syasuda-tok1-vpc1 ~]# oc run samplepod2 --image=private.icr.io/ext/istio/examples-bookinfo-reviews-v3:1.15.0

[root@new-syasuda-tok1-vpc1 ~]# oc describe pod samplepod2
(途中略)
Events:
  Type     Reason          Age                      From               Message
  ----     ------          ----                     ----               -------
  Normal   Scheduled       36s                      default-scheduler  Successfully assigned testproject1/samplepod2 to 10.0.0.25 by kube-scheduler-794dfbddfd-7sgsv
  Normal   AddedInterface  36s                      multus             Add eth0 [172.17.34.31/32] from k8s-pod-network
  Normal   BackOff         6s (x2 over 34s)         kubelet            Back-off pulling image "private.icr.io/ext/istio/examples-bookinfo-reviews-v3:1.15.0"
  Warning  Failed          6s (x2 over 34s)         kubelet            Error: ImagePullBackOff
  Normal   Pulling         <invalid> (x3 over 35s)  kubelet            Pulling image "private.icr.io/ext/istio/examples-bookinfo-reviews-v3:1.15.0"
  Warning  Failed          <invalid> (x3 over 34s)  kubelet            Failed to pull image "private.icr.io/ext/istio/examples-bookinfo-reviews-v3:1.15.0": rpc error: code = Unknown desc = unable to retrieve auth token: invalid username/password: unauthorized: The login credentials are not valid, or your IBM Cloud account is not active.
  Warning  Failed          <invalid> (x3 over 34s)  kubelet            Error: ErrImagePull

3. アクセスできる理由はノード構成にある

結局、この辺りはkubeletのノード側の構成にあるのではないだろうかと想像して、ノードの中を探ってみたらビンゴだった。

ノードにログイン
[root@new-syasuda-tok1-vpc1 ~]# oc debug -t  node/10.0.0.25 -- chroot /host
一般的なkubeletの構成情報は/var/lib/kubelet配下にあるが、以下のように/var/data/kubeletにシンボリックリンクが張られている。
sh-4.4# ls -ld /var/lib/kubelet
lrwxrwxrwx. 1 root root 17 Oct  4 17:35 /var/lib/kubelet -> /var/data/kubelet
/var/data/kubeletをルートディレクトリとしてkubeletは起動されている
sh-4.4# ps -ef|grep kubelet.conf |grep -v grep
root       7978      1  9 Oct04 ?        5-08:36:25 kubelet --config=/etc/kubernetes/kubelet.conf --root-dir=/var/data/kubelet --v=2 --kubeconfig=/etc/kubernetes/kubelet-kubeconfig --hostname-override=10.0.0.25 --cloud-provider=external --container-runtime=remote --container-runtime-endpoint=/var/run/crio/crio.sock --runtime-cgroups=/podruntime.slice
/var/data/kubelet配下にconfig.jsonがある
sh-4.4# ls -l /var/data/kubelet
total 32
-rw-------.  1 root root 3533 Oct  4 17:36 config.json
-rw-------.  1 root root   62 Oct  4 17:36 cpu_manager_state
drwxr-xr-x.  2 root root 4096 Oct  4 17:36 device-plugins
-rw-------.  1 root root   61 Oct  4 17:36 memory_manager_state
drwxr-x---.  2 root root 4096 Oct  4 17:36 plugins
drwxr-x---.  2 root root 4096 Oct  4 17:36 plugins_registry
drwxr-x---.  2 root root 4096 Oct  4 17:36 pod-resources
drwxr-x---. 60 root root 4096 Nov 24 23:45 pods
icr.ioに関する認証情報が含まれていた!
sh-4.4# cat /var/data/kubelet/config.json | jq
{
  "auths": {
    "cloud.openshift.com": {
      "auth": "<data>"
    },
    "quay.io": {
      "auth": "<data>"
    },
    "registry.connect.redhat.com": {
      "auth": "<data>"
    },
    "registry.redhat.io": {
      "auth": "<data>"
    },
    "icr.io": {
      "auth": "<data>"
    },
    "registry.bluemix.net": {
      "auth": "<data>"
    },
    "registry.au-syd.bluemix.net": {
      "auth": "<data>"
    },
    "registry.eu-gb.bluemix.net": {
      "auth": "<data>"
    },
    "registry.eu-de.bluemix.net": {
      "auth": "<data>"
    },
    "registry.ng.bluemix.net": {
      "auth": "<data>"
    }
  }
}
認証情報はiamapikey:<キー情報>の形式で記述されたものをbase64でエンコードして保管されている。
sh-4.4# cat /var/data/kubelet/config.json | jq -r '.auths."icr.io".auth' | base64 -d
iamapikey:<API Key情報>

icr.ioにアクセスできるからといっても、当然構成されているAPIKeyの権限でアクセスできるイメージにしかアクセスできないはずである。おそらくicr.io/extなどのイメージしかアクセスできないのだろう。念のため、この情報を使ってicr.io(IBM Cloud Container Registry)にアクセスできることも確認してみた。

worker nodeにあるconfig.jsonを使ってICRにログインする
[root@new-syasuda-tok1-vpc1 ~]# ibmcloud login --apikey $(oc debug -t node/10.0.0.25 -- chroot host cat /var/data/kubelet/config.json | jq -r '.auths."icr.io".auth' | base64 -d| cut -f 2 -d ":")


[root@new-syasuda-tok1-vpc1 ~]# ibmcloud cr info

Plugin version                    1.0.2
Container Registry                icr.io
Container Registry API endpoint   https://icr.io/api
IBM Cloud API endpoint            https://cloud.ibm.com
IBM Cloud account details         Argonauts Production 531277 (e223e119c9be31669e5688bb376411f7)

[root@new-syasuda-tok1-vpc1 ~]# ibmcloud cr images --restrict ext/sysdig/agent | grep -e Tag -e latest
Repository                Tag        Digest         Namespace   Created         Size     Security status
icr.io/ext/sysdig/agent   latest     45b10702667b   ext         2 weeks ago     696 MB   -

[root@new-syasuda-tok1-vpc1 ~]# ibmcloud cr images --restrict ext/logdna-agent | grep -e Tag -e stable
Repository                Tag                                                          Digest         Namespace   Created         Size     Security status
icr.io/ext/logdna-agent   stable                                                       48deacca9636   ext         1 day ago       125 MB   -
icr.io/ext/logdna-agent   v2-stable                                                    48deacca9636   ext         1 day ago       125 MB   -

[root@new-syasuda-tok1-vpc1 ~]# ibmcloud cr images --restrict ext/istio/examples-bookinfo-reviews-v3 | grep -e Tag -e 1.15.0
Repository                                      Tag      Digest         Namespace   Created       Size     Security status
icr.io/ext/istio/examples-bookinfo-reviews-v3   1.15.0   e454cab754cf   ext         3 years ago   329 MB   -
5
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?