😎

ICTSC 2024 本線 Writeup

に公開

はじめに

つい先日ICTSC2024の本戦に参加してきたので、そのWriteup記事です。
「結束baud」というチームで5人で参加してきました。
結果としては、4位でした。3位と90点差だったので悔しい... 来年は優勝🏆を目指します!
結果

参加した感想

全体の印象としては、去年よりも問題数が多くて全部解ききれなかったのが苦しかったです。
ただ、つよつよのチームメンバーのお陰でなんとか大体の問題は提出できたので良かったです。
あと、物理問題が比較的増えていてLANケーブルの配線とかあったのが印象的でした。
来年はもっと高速にLANケーブルが作れるように修行してきます🧘

解いた問題

去年は全然解けず椅子温め係になっていたので、今回は色々と問題解けたのでよかったです。
私が解いた問題は以下です。大体7問ぐらい?
主にサーバー系の問題を解いてました。普段k8sとか良く触ってるのでk8s問頑張るぞ!と意気込んでもしたが、1問しかなくて悲しかったです😭

  • DGR: podが起動できない
  • DNB: アイデンティティの喪失
  • DXZ: IPv6の自動アドレス設定ってややこしい(一部だけ)
  • AZW: VM畑でつかまえて
  • BKT: リンクの迷宮
  • RJB: プロモ苦す、Proxmox
  • OMV: おきのどくですがWebサーバーの証明書は切れてしまいました
  • JKI: 証明書を二つも使っちゃいます!

DGR: podが起動できない

問題文

概要

友人から「プライベートレジストリのコンテナイメージを Kubernetes 上で使用したいが、うまくいかない」と相談を受けました。友人は、HTTPS での運用は少し面倒だと考え、HTTP で運用しようとしていますが、検証がうまく進んでいないようです。どうにかして友人を助けてあげてください。

前提条件

https://の url を使用し、レジストリに接続しないこと

初期状態

$ curl 192.168.8.1:8080 をしても応答がない

終了状態

$ curl 192.168.8.1:8080 をすると Welcome to nginx!と表示できるようにすること

補足

Kubernetesと同じホスト上に、dockerを使ってHarborでプライベートレジストリが構築されていました。

感想

ちょうど似たようなことを研究室でやったことがあって、同じ問題に当たったのでなんとなく解決方法の予想がつきました。
kindを触ったのは初めてでしたが、比較的順調に行けました。
なお、HarborのRegistryのポート番号を何故か5000番だと思い込んでいて謎に時間が溶けました...

解答

この問題は、kindで利用しているContainerdでプライベートレジストリがInsecure Registryに追加されていなかったことが問題でした。

以下の手順で解決できました。

  1. まず、kindの~/kind/config.yamlを変更し、Insecure registryに追加してhttpで接続できるようにします。
@@ -9,5 +9,11 @@
   - hostPath: /home/user/kind/hosts
     containerPath: /etc/hosts
     readOnly: false
 - role: worker
 - role: worker
+containerdConfigPatches:
+  - |
+    [plugins."io.containerd.grpc.v1.cri".registry.mirrors."registry.ictsc.internal"]
+      endpoint = ["http://registry.ictsc.internal"]
+    [plugins."io.containerd.grpc.v1.cri".registry.configs."registry.ictsc.internal".tls]
+      insecure_skip_verify = true
  1. 次に設定を反映させるために、kindでClusterを再作成します。
$ cd kind
$ kind delete cluster
Deleting cluster "kind" ...
Deleted nodes: ["kind-worker2" "kind-worker" "kind-control-plane"]
$ kind create cluster --config config.yaml 
Creating cluster "kind" ...
 ✓ Ensuring node image (kindest/node:v1.32.0) 🖼 
 ✓ Preparing nodes 📦 📦 📦  
 ✓ Writing configuration 📜 
 ✓ Starting control-plane 🕹️ 
 ✓ Installing CNI 🔌 
 ✓ Installing StorageClass 💾 
 ✓ Joining worker nodes 🚜 
httSet kubectl context to "kind-kind"
You can now use your cluster with:
kubectl cluster-info --context kind-kind
Thanks for using kind! 😊
  1. 最後にManifestをapplyします
$ cd ~
$ kubectl apply -f nginx.yaml 
deployment.apps/nginx-deployment created
service/nginx-service created

これで、Nginxが起動してホームページが見れることを確認できました。

$ kubectl get pods 
NAME                                READY   STATUS    RESTARTS   AGE
nginx-deployment-84c565b7f8-swbll   1/1     Running   0          2m14s
$ curl 192.168.8.1:8080
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>

DNB: アイデンティティの喪失

問題

概要

新人のT君はLDAPの構築を任されましたが、どうやらうまく設定ができていないようです。正常に設定を完了させ、ユーザーがログインできるようにしてください。

前提条件

OpenLDAPを用いてLDAPサーバーを構築しています。
OpenLDAP以外のLDAPサーバーをインストールし構築することは禁止です。
LDAPを使わずに当該ユーザーがログインできるようにすることも禁止です。(useraddや/etc/passwd変更など)
サーバーとクライアントを同居させていることに特段意味はありません。

初期状態

ssh alice@localhostやsu aliceが失敗する
具体的には、user alice does not exist (以下略)やPermission denied, please try again.などと表示される。

終了状態

ssh alice@localhostやsu aliceでログインができる (部分点 100点)
ssh alice@localhostやsu aliceした際にグループが存在しないエラーメッセージが出ない (部分点 50点)

補足

最初に入っていたLDAPのエントリは以下の通りです。

 dn: dc=ictsc,dc=net
 objectClass: top
 objectClass: dcObject
 objectClass: organization
 o: ictsc
 dc: ictsc
 structuralObjectClass: organization
 entryUUID: 8e4a60c2-8d1e-103f-9bb7-9ff3c415d09f
 creatorsName: cn=admin,dc=ictsc,dc=net
 createTimestamp: 20250304082938Z
 entryCSN: 20250304082938.354512Z#000000#000#000000
 modifiersName: cn=admin,dc=ictsc,dc=net
 modifyTimestamp: 20250304082938Z
 dn: ou=People,dc=ictsc,dc=net
 ou: People
 objectClass: top
 objectClass: organizationalUnit
 structuralObjectClass: organizationalUnit
 entryUUID: a741e3d0-8d2c-103f-8281-8569c8b44bb6
 creatorsName: cn=admin,dc=ictsc,dc=net
 createTimestamp: 20250304101033Z
 entryCSN: 20250304101033.196158Z#000000#000#000000
 modifiersName: cn=admin,dc=ictsc,dc=net
 modifyTimestamp: 20250304101033Z
 dn: ou=Group,dc=ictsc,dc=net
 ou: Group
 objectClass: top
 objectClass: organizationalUnit
 structuralObjectClass: organizationalUnit
 entryUUID: a74426b8-8d2c-103f-8282-8569c8b44bb6
 creatorsName: cn=admin,dc=ictsc,dc=net
 createTimestamp: 20250304101033Z
 entryCSN: 20250304101033.211003Z#000000#000#000000
 modifiersName: cn=admin,dc=ictsc,dc=net
 modifyTimestamp: 20250304101033Z
 dn: uid=alice,ou=People,dc=ictsc,dc=net
 objectClass: top
 objectClass: person
 objectClass: organizationalPerson
 objectClass: inetOrgPerson
 objectClass: posixAccount
 objectClass: shadowAccount
 uid: alice
 cn: alice
 sn: alice
 givenName: alice
 title: alice
 telephoneNumber: +0 000 000 0000
 mobile: +0 000 000 0000
 postalAddress: none
 userPassword: {SSHA}oK7MLwL8ALiREC4UltRW00iZdUANhaAD
 labeledURI: https://icttoracon.net/
 loginShell: /bin/bash
 uidNumber: 9999
 gidNumber: 9999
 homeDirectory: /home/alice/
 description: This is an example user
 structuralObjectClass: inetOrgPerson
 entryUUID: 6297a426-8d2d-103f-8283-8569c8b44bb6
 creatorsName: cn=admin,dc=ictsc,dc=net
 createTimestamp: 20250304101547Z
 entryCSN: 20250304101547.492097Z#000000#000#000000
 modifiersName: cn=admin,dc=ictsc,dc=net
 modifyTimestamp: 20250304101547Z
 dn: cn=customer,ou=Group,dc=ictsc,dc=net
 objectClass: top
 objectClass: posixGroup
 cn: customer
 gidNumber: 9999
 structuralObjectClass: posixGroup
 entryUUID: ac45596a-8d2d-103f-8285-8569c8b44bb6
 creatorsName: cn=admin,dc=ictsc,dc=net
 createTimestamp: 20250304101751Z
 entryCSN: 20250304101751.104200Z#000000#000#000000
 modifiersName: cn=admin,dc=ictsc,dc=net
 modifyTimestamp: 20250304101751Z

感想

苦しい...
まずcn=admin,dc=ictsc,dc=netのパスワードが不明なので、とりあえずLDAPをリセットしました。エスパーできないかと思ったけど、やめました。
そこから、初期条件を満たすようにエントリを再投入したので結構時間かかってしまって苦しかったです。
LDAPさえ何とかなれば後は簡単です。
LDAP認証するならSSSDを使ってもよかったんですが、今回はnslcdでやりました。

解答

今回の原因はnslcdにてクライアントの設定がされていなかったことが原因でした。

以下の手順で解決できました。

  1. まず、cn=admin,dc=ictsc,dc=netのパスワードが不明なため、以下のコマンドを実行してLDAPを構成を再設定します。
    この時に、管理者パスワードをictsc2024に指定しました。
$ sudo dpkg-reconfigure slapd
  1. 次にLDAPサーバーに対して必要なグループ、ユーザの情報を登録します。

以下のファイルをconfig.ldifとして保存します。
なお、aliceのuserpasswordはslappasswdコマンドを用いてハッシュ値を取得します。

dn: ou=People,dc=ictsc,dc=net
ou: People
objectClass: top
objectClass: organizationalUnit

dn: ou=Group,dc=ictsc,dc=net
ou: Group
objectClass: top
objectClass: organizationalUnit

dn: uid=alice,ou=People,dc=ictsc,dc=net
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: shadowAccount
uid: alice
cn: alice
sn: alice
givenName: alice
title: alice
telephoneNumber: +0 000 000 0000
mobile: +0 000 000 0000
postalAddress: none
userPassword: {SSHA}KXbkGOtOFKcqy5O3xC5G4Z+dpqplWgvS
labeledURI: https://icttoracon.net/
loginShell: /bin/bash
uidNumber: 9999
gidNumber: 9999
homeDirectory: /home/alice/
description: This is an example user

dn: cn=customer,ou=Group,dc=ictsc,dc=net
objectClass: top
objectClass: posixGroup
cn: customer
gidNumber: 9999

作成したファイルを以下のコマンドで登録します。
この時、1で指定した管理者パスワードを利用します。

$ ldapadd -x -D cn=admin,dc=ictsc,dc=net -W -f config.ldif
  1. nslcd.confの設定を変更します。
    sudo vim /etc/nslcd.confで以下のように変更します。
# /etc/nslcd.conf
# nslcd configuration file. See nslcd.conf(5)
# for details.
# The user and group nslcd should run as.
uid nslcd
gid nslcd
# The location at which the LDAP server(s) should be reachable.
uri ldap:///127.0.0.1
# The search base that will be used for all queries.
base dc=ictsc,dc=net
# The LDAP protocol version to use.
#ldap_version 3
# The DN to bind with for normal lookups.
binddn cn=admin,dc=ictsc,dc=net
bindpw ictsc2024
# The DN used for password modifications by root.
#rootpwmoddn cn=admin,dc=example,dc=com
# SSL options
#ssl off
#tls_reqcert never
tls_cacertfile /etc/ssl/certs/ca-certificates.crt
# The search scope.
#scope sub
  1. nsswitchの設定を変更します。
    sudo vim cat /etc/nsswitch.confで以下の行を追加します。
    これによりLDAPのグループが認識されます。
passwd:         files systemd ldap
+ group:          files systemd ldap
shadow:         files systemd ldap
  1. 最後に設定を反映させるため、nslcdを再起動します。
sudo stemctl restart nslcd

aliceとしてログインして、エラーが出ないことを確認します。

user@dnb-server:~$ su alice
Password: ictsc2024
alice@dnb-server:/home/user$ 

DXZ: IPv6の自動アドレス設定ってややこしい

問題

概要

小村君は自宅のネットワークを, IPv6 mostly の環境にしたいと考えている.
ひとまず, 検証として VyOS で IPv6 アドレスの自動設定を試してみることにした. DHCPv6 で自動設定を行ったところ, 自身のスマートフォンにユニークローカル IPv6 ユニキャストアドレスが振られていないことに気づいた.

以下の作業をし,その手順を報告してください.

  • dev(スマートフォン)にfd00:ad:e:25::/64 の IPv6 アドレスと DNS サーバ情報が自動設定されるように router のトラブルシューティングをする.
  • dev(スマートフォン)から router へrouter.ictsc.internal, server へserver.ictsc.internalで疎通できるようにトラブルシューティングをする.

※なお, dev はスマートフォンの IPv6 設定を模したものである.

前提条件

  • dev(スマートフォン)の設定を変更してはならない
  • ネットワークの構成ノード・アドレスはトポロジー図に示されたものを使うこと
  • アドレス自動設定は、router の VyOS で設定すること
  • DNS サーバ(名前解決)は、server にすでに導入済みの unbound を使用すること

初期状態

  • dev(スマートフォン)から以下に疎通できない.
    • router への$ ping6 fd00:ad:e:25::2
    • router への$ ping6 router.ictsc.internal
    • server への$ ping6 fd00:ad:e:25::3
    • server への$ ping6 server.ictsc.internal

終了状態

  • dev(スマートフォン)にfd00:ad:e:25::/64 の IPv6 アドレスが自動で振られている.
  • dev(Android)から以下のコマンドで疎通できる.
    • router への$ ping6 fd00:ad:e:25::2
    • router への$ ping6 router.ictsc.internal
    • server への$ ping6 fd00:ad:e:25::3
    • server への$ ping6 server.ictsc.internal

補足情報

初期コンフィグ

code: config
 user@vyos:~$ show configuration 
 interfaces {
     ethernet eth0 {
         address dhcp
         address 192.168.25.2/24
         address fd00:d056:6:0025::2/64
         hw-id bc:24:11:53:b1:a7
         offload {
             gro
             gso
             sg
             tso
         }
     }
     ethernet eth1 {
         address fd00:ad:e:25::2/64
         address 192.168.125.2/24
         hw-id bc:24:11:23:2a:0a
     }
     loopback lo {
     }
 }
 protocols {
     static {
         route 0.0.0.0/0 {
             next-hop 192.168.25.254 {
             }
         }
         route6 ::/0 {
             next-hop fd00:d056:6:0025::ffff {
             }
         }
     }
 }
 service {
     dhcpv6-server {
         shared-network-name DHCPV6_POOL {
             interface eth0
             subnet fd00:ad:e:25::/64 {
                 option {
                     name-server fd00:ad:e:25::3
                 }
                 range 1 {
                     start fd00:ad:e:25::100
                     stop fd00:ad:e:25::199
                 }
                 subnet-id 1
             }
         }
     }
     ntp {
         allow-client {
             address 127.0.0.0/8
             address 169.254.0.0/16
             address 10.0.0.0/8
             address 172.16.0.0/12
             address 192.168.0.0/16
             address ::1/128
             address fe80::/10
             address fc00::/7
         }
         server time1.vyos.net {
         }
         server time2.vyos.net {
         }
         server time3.vyos.net {
         }
     }
     ssh {
     }
 }
 system {
     config-management {
     }
     console {
         device ttyS0 {
             speed 115200
         }
     }
     host-name vyos
     login {
         banner {
             post-login "██╗ ██████╗████████╗███████╗ ██████╗ \n██║██╔════╝╚══██╔══╝██╔════╝██╔════╝ \n██║██║        ██║   ███████╗██║      \n██║██║        ██║   ╚════██║██║      \n██║╚██████╗   ██║   ███████║╚██████╗ \n╚═╝ ╚═════╝   ╚═╝   ╚══════╝ ╚═════╝ \n                                     \n    ██████╗  ██████╗ ██████╗ ██╗  ██╗\n    ╚════██╗██╔═████╗╚════██╗██║  ██║\n     █████╔╝██║██╔██║ █████╔╝███████║\n    ██╔═══╝ ████╔╝██║██╔═══╝ ╚════██║\n    ███████╗╚██████╔╝███████╗     ██║\n    ╚══════╝ ╚═════╝ ╚══════╝     ╚═╝"
         }
         user ictsc {
             authentication {
                 encrypted-password ****************
                 public-keys default {
                     key ****************
                     type ssh-rsa
                 }
             }
         }
         user user {
             authentication {
                 encrypted-password ****************
                 public-keys default {
                     key ****************
                     type ssh-rsa
                 }
             }
         }
         user vyos {
             authentication {
                 encrypted-password ****************
                 plaintext-password ****************
                 public-keys ictsc2024 {
                     key ****************
                     type ssh-rsa
                 }
             }
         }
     }
     option {
         keyboard-layout jp106
     }
     syslog {
         global {
             facility all {
                 level info
             }
             facility local7 {
                 level debug
             }
         }
     }
     time-zone Asia/Tokyo
 }

感想

この問題は途中から引き継いだもので、ネットワーク周りの問題は解決した上で最後のUnboundで名前解決できないところを解決しました。
とりあえず、Unboundの設定を見てみたところZoneが怪しかったので直しました。
あとは、devからdigでUnboundサーバーを指定しても権限なしで解決できなかったので、おかしいなと思ってnmapで調べてみました。
Vyosとdevからそれぞれnmapしてみるとfiltedになっていて、unboundのサーバーからやるとopenになっていました。Firewallかな?という推測をして、その通りでした。

解答

以下の手順によって解決することができました。

  1. Routerに接続して設定を変更する

DHCPv6 ServerのInterfaceがeth0になっていたため、eth1に修正した。また、RAするようにするためDHCPv6を使うように修正した。

service {
   dhcpv6-server {
       shared-network-name DHCPV6_POOL {
           interface eth1
           subnet fd00:ad:e:25::/64 {
               option {
                   name-server fd00:ad:e:25::3
               }
               range 1 {
                   start fd00:ad:e:25::100
                   stop fd00:ad:e:25::199
               }
               subnet-id 1
           }
       }
   }
   router-advert {
       interface eth1 {
           default-preference high
           managed-flag
           other-config-flag
       }
   }

設定後は、以下のコマンドを実行し、変更した設定を反映させます。

user@vyos:~$ commit
user@vyos:~$ save
  1. ServerがIPv6アドレスを利用するように設定を変更する
    サーバーに接続し、ServerがDHCPv6を使うようにするため以下の設定を追加します。
sudo nmcli connection modify System\ eth1 ipv6.addresses fd00:ad:e:25::3/64
sudo nmcli connection modify System\ eth1 ipv6.method manual
sudo nmcli connection down System\ eth1 
sudo nmcli connection up System\ eth1
  1. Unboundの設定を修正する
    /etc/unbound/unbound.confで、Local Zoneの設定が誤っていたため設定ファイルを修正します。
-  local-zone: "ictsc.net." static
+  local-zone: "ictsc.internal." static

変更後は、unboundを再起動して反映させます。

$ sudo systemctl restart unbound
  1. 最後にFirewalledを修正して、ServerへDNSのクエリが通るようにします
$ sudo firewall-cmd --permanent --add-service=dns
$ sudo firewall-cmd --reload

devからそれぞれ疎通ができることを確認します。

user@dev:~$ ping6 fd00:ad:e:25::2 -c 5
PING fd00:ad:e:25::2 (fd00:ad:e:25::2) 56 data bytes
64 bytes from fd00:ad:e:25::2: icmp_seq=1 ttl=64 time=0.386 ms
64 bytes from fd00:ad:e:25::2: icmp_seq=2 ttl=64 time=0.319 ms
64 bytes from fd00:ad:e:25::2: icmp_seq=3 ttl=64 time=0.281 ms
64 bytes from fd00:ad:e:25::2: icmp_seq=4 ttl=64 time=0.281 ms
64 bytes from fd00:ad:e:25::2: icmp_seq=5 ttl=64 time=0.280 ms
--- fd00:ad:e:25::2 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4105ms
rtt min/avg/max/mdev = 0.280/0.309/0.386/0.041 ms
user@dev:~$ ping6 router.ictsc.internal -c 5
PING router.ictsc.internal (fd00:ad:e:25::2) 56 data bytes
64 bytes from router.ictsc.internal (fd00:ad:e:25::2): icmp_seq=1 ttl=64 time=0.348 ms
64 bytes from router.ictsc.internal (fd00:ad:e:25::2): icmp_seq=2 ttl=64 time=0.388 ms
64 bytes from router.ictsc.internal (fd00:ad:e:25::2): icmp_seq=3 ttl=64 time=0.410 ms
64 bytes from router.ictsc.internal (fd00:ad:e:25::2): icmp_seq=4 ttl=64 time=0.360 ms
64 bytes from router.ictsc.internal (fd00:ad:e:25::2): icmp_seq=5 ttl=64 time=0.417 ms
--- router.ictsc.internal ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4073ms
rtt min/avg/max/mdev = 0.348/0.384/0.417/0.027 ms
user@dev:~$ ping6 fd00:ad:e:25::3 -c 5
PING fd00:ad:e:25::3 (fd00:ad:e:25::3) 56 data bytes
64 bytes from fd00:ad:e:25::3: icmp_seq=1 ttl=64 time=0.615 ms
64 bytes from fd00:ad:e:25::3: icmp_seq=2 ttl=64 time=0.565 ms
64 bytes from fd00:ad:e:25::3: icmp_seq=3 ttl=64 time=0.384 ms
64 bytes from fd00:ad:e:25::3: icmp_seq=4 ttl=64 time=0.484 ms
64 bytes from fd00:ad:e:25::3: icmp_seq=5 ttl=64 time=0.549 ms
--- fd00:ad:e:25::3 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4077ms
rtt min/avg/max/mdev = 0.384/0.519/0.615/0.079 ms
user@dev:~$ ping6 server.ictsc.internal -c 5
PING server.ictsc.internal (fd00:ad:e:25::3) 56 data bytes
64 bytes from server.ictsc.internal (fd00:ad:e:25::3): icmp_seq=1 ttl=64 time=0.248 ms
64 bytes from server.ictsc.internal (fd00:ad:e:25::3): icmp_seq=2 ttl=64 time=0.661 ms
64 bytes from server.ictsc.internal (fd00:ad:e:25::3): icmp_seq=3 ttl=64 time=0.666 ms
64 bytes from server.ictsc.internal (fd00:ad:e:25::3): icmp_seq=4 ttl=64 time=0.550 ms
64 bytes from server.ictsc.internal (fd00:ad:e:25::3): icmp_seq=5 ttl=64 time=0.445 ms
--- server.ictsc.internal ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4063ms
rtt min/avg/max/mdev = 0.248/0.514/0.666/0.155 ms

AZW: VM畑でつかまえて

問題

概要

A さんはオンラインオークションサイトで念願のラックサーバを手に入れた!莫大なサイズのメモリが搭載されているため、VM をどれだけ作っても枯渇しないだろうと考えるとワクワクが止まらない様子。早速 VM を 2 つ作ってひとまず両者の間で通信をさせてみようと考え、A さんはまずテンプレートとなる VM を作成した。次に、テンプレートを 2 回クローンして 2 つの VM vm1 と vm2 を作成した。その後、bridge interface をそれぞれの VM で 1 つずつ作成し、IP アドレスをアサインするための設定を書いた。

早速、相手の VM と通信できるか試してみたところ、なぜか繋がらなかった。ネットワークインターフェイスに割り当てた IP アドレスの設定を何度見直しても間違いはないと A さんは言う。

ちなみに、A さんは設定より規約という考え方と systemd-networkd が好きで、ip コマンドを叩いたセットアップは極力したくないらしい。

A さんのワクワクが止まらないうち(具体的には、ICTSC2024 本戦競技時間中)に、原因究明と解決策の適用、およびそれらの報告を行いなさい。

前提条件

/etc/systemd/network 以下でファイルの作成・編集・削除を行わないこと
ip コマンドや netplan、NetworkManager などの、systemd-networkd 以外を用いたネットワークインターフェイスの設定をしないこと
再起動後に終了状態が継続していること

初期状態

vm1 で $ ping 10.0.1.1 を実行しても返答がない。また、vm2 で $ ping 10.0.1.0 を実行しても返答がない。

終了状態

vm1 で $ ping 10.0.1.1 を実行すると返答がある。また、vm2 で $ ping 10.0.1.0 を実行すると返答がある。

また、再起動後にも上記の状態が継続していることが確認できる。

感想

ProxmoxでVMをCloneした際に似たような問題に直面することがあったのですが、netplanの大体MACアドレスを書き換えて対応してたのでこの問題で根本的な問題を学べてよかったです。
何回再起動してもMACアドレスが同じになるので、何かがSeed値になっているのかな?と疑いました。
ChatGPTに聞いてみると、machine-idのことを教えてくれたので助かりました。

P.S. 問題文を見た瞬間、ういままの波動を感じたので解きました。みんな聞いてね!
https://www.youtube.com/watch?v=5uaHMmcReI0
(追記:これライ麦畑が元ネタっぽいらしいですね)

解答

この問題は、2つのVMのmachine-idが同一であったため自動生成されるMACアドレスが衝突していたのが原因だと考えられます。

以下の手順で解決できました。

  1. VM2でmachine-idを再作成する
    machine-idを再作成したのちに、MACアドレスの際割り当てをするため一度VM2を再起動します。
sudo rm /etc/machine-id
sudo systemd-machine-id-setup
sudo reboot
  1. 2つのVMでMACアドレスが衝突していないことを確認します。
user@vm1:~$ ip link show br0
4: br0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
 link/ether 1e:60:3c:dd:53:2f brd ff:ff:ff:ff:ff:ff
user@vm2:~$ ip link show br0
4: br0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
 link/ether ce:4c:de:c1:04:10 brd ff:ff:ff:ff:ff:ff
  1. 最後にそれぞれのVMからpingの疎通を確認します。
user@vm1:~$ ping 10.0.1.1 -c 5
PING 10.0.1.1 (10.0.1.1) 56(84) bytes of data.
64 bytes from 10.0.1.1: icmp_seq=1 ttl=64 time=0.427 ms
64 bytes from 10.0.1.1: icmp_seq=2 ttl=64 time=0.380 ms
64 bytes from 10.0.1.1: icmp_seq=3 ttl=64 time=0.221 ms
64 bytes from 10.0.1.1: icmp_seq=4 ttl=64 time=0.303 ms
64 bytes from 10.0.1.1: icmp_seq=5 ttl=64 time=0.304 ms
--- 10.0.1.1 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4135ms
rtt min/avg/max/mdev = 0.221/0.327/0.427/0.070 ms

user@vm2:~$ ping 10.0.1.0 -c 5
PING 10.0.1.0 (10.0.1.0) 56(84) bytes of data.
64 bytes from 10.0.1.0: icmp_seq=1 ttl=64 time=0.209 ms
64 bytes from 10.0.1.0: icmp_seq=2 ttl=64 time=0.270 ms
64 bytes from 10.0.1.0: icmp_seq=3 ttl=64 time=0.377 ms
64 bytes from 10.0.1.0: icmp_seq=4 ttl=64 time=0.251 ms
64 bytes from 10.0.1.0: icmp_seq=5 ttl=64 time=0.619 ms
--- 10.0.1.0 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4090ms
rtt min/avg/max/mdev = 0.209/0.345/0.619/0.147 ms

BKT: リンクの迷宮

問題文

概要

ICTSC2024 本戦の手元問題で使用するスイッチを設定していたところ、原因不明でリンク速度が 100Mbps になってしまった。
原因を特定し、参加者に快適なネットワーク環境を提供してください。

前提条件

使用するポートは以下の通り

C841-1
Gi0/3
Nexus93108
Eth1/5

制約

使用するスイッチのポートを変更してはいけない

初期状態

C841-1 Gi0/3Nexus93108 Eth1/5 間が 100Mbps でリンクアップする

終了状態

C841-1 Gi0/3Nexus93108 Eth1/5 間が 1000Mbps でリンクアップする
本問題の原因を特定し再発防止策を講じるために、この問題が再現できるよう詳細な報告書を作成すること

補足

この問題は物理問題なので、会場にある機材にコンソールで接続して解答します。
こんな感じの機材です。上からC841-1、C841-2、Nexus93108です。

感想

100Mbpsでリンクをしてる&会場のLANケーブルの作成コーナがあるという時点でなんとなく察せますよね?
LANケーブルを作った人なら経験があると思うのですが、結線をミスると100Mbpsでしかリンクしないので多分この問題もそうなんだろうなぁと思って、とりあえず最初に繋がってる線を持ってかしめコーナーへ向かいました。

最初繋がってたケーブルをテストした様子

予想通り結線がミスってますね
https://www.youtube.com/watch?v=ZbzozCf1DbA

かしめコーナーの様子

ELECOMのかしめ工具がありました。ニッパー欲しかった...
最初に外側の被覆剥くやつで何回か芯線切って失敗しました
https://x.com/icttoracon/status/1901098342974673359

解答

この問題は以下の2点が問題でした。

  1. 使用しているLANケーブルの結線が誤っていた
  2. N9Kでリンクスピードが100Mbpsになっていた

以下の手順で解決できました。

  1. LANケーブルを正しいものに変更する
    初期状態で利用されていたLANケーブルの両端ABの結線を、ケーブルテスターを用いて調べたところ、
    A: 12345678
    B: 12365478
    のような結果となっていました。
    これは、2組のツイストペアが存在しており、100Base-TXとして100Mbpsで通信が可能ですが、1000Mbpsで通信するためには4組のペアを用いた1000BASE-Tを用いる必要があります。
    かしめコーナーにて、両側をT-568Bの結線に揃えたLANケーブルを作成し接続しました。

  2. N9Kでリンクスピードを1000Mbpsにする。
    N9Kの設定を確認したところ、100Mbpsで通信が行われるようになっていました。
    以下のように設定を変更し、1000Mbpsでリンクするようにしました。

n9k# conf t
Enter configuration commands, one per line. End with CNTL/Z.
n9k(config)# interface Ethernet1/5
n9k(config-if)# no speed 100
n9k(config-if)# exit

最後にC841-1でリンクスピードを確認したところ、1000Mbpsで通信できていることが確認できました。

c841-1#show interface GigabitEthernet 0/3
GigabitEthernet0/3 is up, line protocol is up 
  Hardware is Gigabit Ethernet, address is 0081.c401.a523 (bia 0081.c401.a523)
  Description: BKT
  MTU 1500 bytes, BW 1000000 Kbit/sec, DLY 10 usec, 
     reliability 255/255, txload 1/255, rxload 1/255
  Encapsulation ARPA, loopback not set
  Keepalive set (10 sec)
  Full-duplex, 1000Mb/s
  ARP type: ARPA, ARP Timeout 04:00:00
  Last input 00:00:35, output never, output hang never
  Last clearing of "show interface" counters never

RJB: プロモ苦す、Proxmox

問題

概要

あなたは Proxmox で多くの Linux Bridge を作成するタスクを与えられました。めんどくさかったので後輩くんにこのタスクを押し付けたところ、後輩くんは手元の機材であるrjb-ubuntuから Proxmox が動作するpveの Web UI にアクセスし、マウスをつかって作成するのもめんどくさいと考え、サッとrjb-ubuntu上で Terraform を実行することで、一気に Linux Bridge を作成しようと考えました。

しかし、後輩くんが$ terraform applyを実行すると、エラーが大量に出現してしまいます。何回か試してみると、terraform.tfstateにきちんとpve上にある Linux Bridge の状態が反映されていなかったり、意図した通りにブリッジが作成されていなかったりします。

このトラブルの原因を突き止めて、解決策と共に後輩くんに教えてあげましょう。

前提条件

Terraform Providerbpg/proxmoxを用いて Proxmox を操作する。
bpg/proxmoxを使わずに Proxmox のリソースを操作することはできない。
bpg/proxmox以外のプロバイダーで Proxmox を操作してはならない。
Proxmox を操作するプロバイダー以外は追加可能。
使用する.tf ファイルは~/terraformに配置されています。

初期状態

rjb-ubuntu上でpveのリソースを操作するため、~/terraformに移動、$ terraform initを実行した後、$ terraforrm applyを実行した際、以下のような問題が発生する。

  • $ terraform apply実行後にエラーが出力される。

terraform.tfstateにpve上の Linux Bridge の状態が反映されない。
作成されないブリッジがある。

終了状態

rjb-ubuntu上で Terraform を実行することにより、pveのリソースをエラーなしで操作できる。

補足

Terraformのエラーメッセージ

│ Error: Error reloading network configuration
 │ 
 │   with proxmox_virtual_environment_network_linux_bridge.vm_bridge_name["vmbr108"],
 │   on hoge.tf line 1, in resource "proxmox_virtual_environment_network_linux_bridge" "vm_bridge_name":
 │    1: resource "proxmox_virtual_environment_network_linux_bridge" "vm_bridge_name" {
 │ 
 │ Could not reload network configuration on node 'pve', unexpected error: failed to reload network configuration for node "pve": All attempts fail:
 │ #1: failed to perform HTTP PUT request (path: nodes/pve/network) - Reason: Put "https://192.168.100.1:8006/api2/json/nodes/pve/network": context deadline exceeded
 ╵

Proxmox側のエラー

TASK ERROR: command 'ifreload -a' failed: exit code 89

感想

ProxmoxをTerraformで使ったことはあったのですが、大量にリソースを作成したことは今回が初めてだったので、この問題は初めて直面しました。
エラーメッセージの内容などから検索をして行って、なんとなく推測をつけて解いて行きました。
Proxmox苦しいですね...

P.S. 懇親会で運営の方から今回の問題環境にProxmoxを用いてTerraformで構築しているという話を聞いて、この問題はそこら辺のトラシューから出た問題なのかなぁと推測してました。

解答

ProxmoxではLinux Bridgeを追加すると、/etc/network/interfacesを編集した後でifreload -aを実行して設定を反映しようとします。
今回の場合Terraformではデフォルトで並列に処理を実行するため、各Linux Bridgeの追加後のifreload -aが並列に行われます。この時、タイミングが被ってしまうとifreload -aが失敗するので、エラーが発生していると考えられます。

Terraformをapplyする際に、以下のようなオプションを追加して、並列で実行しないようにすることで解決できます。

$ terraform apply --parallelism 1
proxmox_virtual_environment_network_linux_bridge.vm_bridge_name["vmbr101"]: Refreshing state... [id=pve:vmbr101]
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# proxmox_virtual_environment_network_linux_bridge.vm_bridge_name["vmbr102"] will be created
+ resource "proxmox_virtual_environment_network_linux_bridge" "vm_bridge_name" {
   + autostart  = true
   + id         = (known after apply)
   + name       = "vmbr102"
   + node_name  = "pve"
   + vlan_aware = (known after apply)
 }
# proxmox_virtual_environment_network_linux_bridge.vm_bridge_name["vmbr103"] will be created
+ resource "proxmox_virtual_environment_network_linux_bridge" "vm_bridge_name" {
   + autostart  = true
   + id         = (known after apply)
   + name       = "vmbr103"
   + node_name  = "pve"
   + vlan_aware = (known after apply)
 }
# proxmox_virtual_environment_network_linux_bridge.vm_bridge_name["vmbr104"] will be created
+ resource "proxmox_virtual_environment_network_linux_bridge" "vm_bridge_name" {
   + autostart  = true
   + id         = (known after apply)
   + name       = "vmbr104"
   + node_name  = "pve"
   + vlan_aware = (known after apply)
 }
# proxmox_virtual_environment_network_linux_bridge.vm_bridge_name["vmbr105"] will be created
+ resource "proxmox_virtual_environment_network_linux_bridge" "vm_bridge_name" {
   + autostart  = true
   + id         = (known after apply)
   + name       = "vmbr105"
   + node_name  = "pve"
   + vlan_aware = (known after apply)
 }
# proxmox_virtual_environment_network_linux_bridge.vm_bridge_name["vmbr106"] will be created
+ resource "proxmox_virtual_environment_network_linux_bridge" "vm_bridge_name" {
   + autostart  = true
   + id         = (known after apply)
   + name       = "vmbr106"
   + node_name  = "pve"
   + vlan_aware = (known after apply)
 }
# proxmox_virtual_environment_network_linux_bridge.vm_bridge_name["vmbr107"] will be created
+ resource "proxmox_virtual_environment_network_linux_bridge" "vm_bridge_name" {
   + autostart  = true
   + id         = (known after apply)
   + name       = "vmbr107"
   + node_name  = "pve"
   + vlan_aware = (known after apply)
 }
# proxmox_virtual_environment_network_linux_bridge.vm_bridge_name["vmbr108"] will be created
+ resource "proxmox_virtual_environment_network_linux_bridge" "vm_bridge_name" {
   + autostart  = true
   + id         = (known after apply)
   + name       = "vmbr108"
   + node_name  = "pve"
   + vlan_aware = (known after apply)
 }
# proxmox_virtual_environment_network_linux_bridge.vm_bridge_name["vmbr109"] will be created
+ resource "proxmox_virtual_environment_network_linux_bridge" "vm_bridge_name" {
   + autostart  = true
   + id         = (known after apply)
   + name       = "vmbr109"
   + node_name  = "pve"
   + vlan_aware = (known after apply)
 }
# proxmox_virtual_environment_network_linux_bridge.vm_bridge_name["vmbr110"] will be created
+ resource "proxmox_virtual_environment_network_linux_bridge" "vm_bridge_name" {
   + autostart  = true
   + id         = (known after apply)
   + name       = "vmbr110"
   + node_name  = "pve"
   + vlan_aware = (known after apply)
 }
# proxmox_virtual_environment_network_linux_bridge.vm_bridge_name["vmbr111"] will be created
+ resource "proxmox_virtual_environment_network_linux_bridge" "vm_bridge_name" {
   + autostart  = true
   + id         = (known after apply)
   + name       = "vmbr111"
   + node_name  = "pve"
   + vlan_aware = (known after apply)
 }
# proxmox_virtual_environment_network_linux_bridge.vm_bridge_name["vmbr112"] will be created
+ resource "proxmox_virtual_environment_network_linux_bridge" "vm_bridge_name" {
   + autostart  = true
   + id         = (known after apply)
   + name       = "vmbr112"
   + node_name  = "pve"
   + vlan_aware = (known after apply)
 }
# proxmox_virtual_environment_network_linux_bridge.vm_bridge_name["vmbr113"] will be created
+ resource "proxmox_virtual_environment_network_linux_bridge" "vm_bridge_name" {
   + autostart  = true
   + id         = (known after apply)
   + name       = "vmbr113"
   + node_name  = "pve"
   + vlan_aware = (known after apply)
 }
# proxmox_virtual_environment_network_linux_bridge.vm_bridge_name["vmbr114"] will be created
+ resource "proxmox_virtual_environment_network_linux_bridge" "vm_bridge_name" {
   + autostart  = true
   + id         = (known after apply)
   + name       = "vmbr114"
   + node_name  = "pve"
   + vlan_aware = (known after apply)
 }
# proxmox_virtual_environment_network_linux_bridge.vm_bridge_name["vmbr115"] will be created
+ resource "proxmox_virtual_environment_network_linux_bridge" "vm_bridge_name" {
   + autostart  = true
   + id         = (known after apply)
   + name       = "vmbr115"
   + node_name  = "pve"
   + vlan_aware = (known after apply)
 }
# proxmox_virtual_environment_network_linux_bridge.vm_bridge_name["vmbr116"] will be created
+ resource "proxmox_virtual_environment_network_linux_bridge" "vm_bridge_name" {
   + autostart  = true
   + id         = (known after apply)
   + name       = "vmbr116"
   + node_name  = "pve"
   + vlan_aware = (known after apply)
 }
# proxmox_virtual_environment_network_linux_bridge.vm_bridge_name["vmbr117"] will be created
+ resource "proxmox_virtual_environment_network_linux_bridge" "vm_bridge_name" {
   + autostart  = true
   + id         = (known after apply)
   + name       = "vmbr117"
   + node_name  = "pve"
   + vlan_aware = (known after apply)
 }
# proxmox_virtual_environment_network_linux_bridge.vm_bridge_name["vmbr118"] will be created
+ resource "proxmox_virtual_environment_network_linux_bridge" "vm_bridge_name" {
   + autostart  = true
   + id         = (known after apply)
   + name       = "vmbr118"
   + node_name  = "pve"
   + vlan_aware = (known after apply)
 }
# proxmox_virtual_environment_network_linux_bridge.vm_bridge_name["vmbr119"] will be created
+ resource "proxmox_virtual_environment_network_linux_bridge" "vm_bridge_name" {
   + autostart  = true
   + id         = (known after apply)
   + name       = "vmbr119"
   + node_name  = "pve"
   + vlan_aware = (known after apply)
 }
# proxmox_virtual_environment_network_linux_bridge.vm_bridge_name["vmbr120"] will be created
+ resource "proxmox_virtual_environment_network_linux_bridge" "vm_bridge_name" {
   + autostart  = true
   + id         = (known after apply)
   + name       = "vmbr120"
   + node_name  = "pve"
   + vlan_aware = (known after apply)
 }
Plan: 19 to add, 0 to change, 0 to destroy.
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value: yes
proxmox_virtual_environment_network_linux_bridge.vm_bridge_name["vmbr110"]: Creating...
proxmox_virtual_environment_network_linux_bridge.vm_bridge_name["vmbr110"]: Creation complete after 2s [id=pve:vmbr110]
proxmox_virtual_environment_network_linux_bridge.vm_bridge_name["vmbr112"]: Creating...
proxmox_virtual_environment_network_linux_bridge.vm_bridge_name["vmbr112"]: Creation complete after 2s [id=pve:vmbr112]
proxmox_virtual_environment_network_linux_bridge.vm_bridge_name["vmbr116"]: Creating...
proxmox_virtual_environment_network_linux_bridge.vm_bridge_name["vmbr116"]: Creation complete after 2s [id=pve:vmbr116]
proxmox_virtual_environment_network_linux_bridge.vm_bridge_name["vmbr111"]: Creating...
proxmox_virtual_environment_network_linux_bridge.vm_bridge_name["vmbr111"]: Creation complete after 2s [id=pve:vmbr111]
proxmox_virtual_environment_network_linux_bridge.vm_bridge_name["vmbr113"]: Creating...
proxmox_virtual_environment_network_linux_bridge.vm_bridge_name["vmbr113"]: Creation complete after 2s [id=pve:vmbr113]
proxmox_virtual_environment_network_linux_bridge.vm_bridge_name["vmbr119"]: Creating...
proxmox_virtual_environment_network_linux_bridge.vm_bridge_name["vmbr119"]: Creation complete after 3s [id=pve:vmbr119]
proxmox_virtual_environment_network_linux_bridge.vm_bridge_name["vmbr109"]: Creating...
proxmox_virtual_environment_network_linux_bridge.vm_bridge_name["vmbr109"]: Creation complete after 3s [id=pve:vmbr109]
proxmox_virtual_environment_network_linux_bridge.vm_bridge_name["vmbr103"]: Creating...
proxmox_virtual_environment_network_linux_bridge.vm_bridge_name["vmbr103"]: Creation complete after 3s [id=pve:vmbr103]
proxmox_virtual_environment_network_linux_bridge.vm_bridge_name["vmbr102"]: Creating...
proxmox_virtual_environment_network_linux_bridge.vm_bridge_name["vmbr102"]: Creation complete after 4s [id=pve:vmbr102]
proxmox_virtual_environment_network_linux_bridge.vm_bridge_name["vmbr115"]: Creating...
proxmox_virtual_environment_network_linux_bridge.vm_bridge_name["vmbr115"]: Creation complete after 3s [id=pve:vmbr115]
proxmox_virtual_environment_network_linux_bridge.vm_bridge_name["vmbr104"]: Creating...
proxmox_virtual_environment_network_linux_bridge.vm_bridge_name["vmbr104"]: Creation complete after 4s [id=pve:vmbr104]
proxmox_virtual_environment_network_linux_bridge.vm_bridge_name["vmbr120"]: Creating...
proxmox_virtual_environment_network_linux_bridge.vm_bridge_name["vmbr120"]: Creation complete after 3s [id=pve:vmbr120]
proxmox_virtual_environment_network_linux_bridge.vm_bridge_name["vmbr118"]: Creating...
proxmox_virtual_environment_network_linux_bridge.vm_bridge_name["vmbr118"]: Creation complete after 3s [id=pve:vmbr118]
proxmox_virtual_environment_network_linux_bridge.vm_bridge_name["vmbr106"]: Creating...
proxmox_virtual_environment_network_linux_bridge.vm_bridge_name["vmbr106"]: Creation complete after 4s [id=pve:vmbr106]
proxmox_virtual_environment_network_linux_bridge.vm_bridge_name["vmbr114"]: Creating...
proxmox_virtual_environment_network_linux_bridge.vm_bridge_name["vmbr114"]: Creation complete after 4s [id=pve:vmbr114]
proxmox_virtual_environment_network_linux_bridge.vm_bridge_name["vmbr107"]: Creating...
proxmox_virtual_environment_network_linux_bridge.vm_bridge_name["vmbr107"]: Creation complete after 4s [id=pve:vmbr107]
proxmox_virtual_environment_network_linux_bridge.vm_bridge_name["vmbr108"]: Creating...
proxmox_virtual_environment_network_linux_bridge.vm_bridge_name["vmbr108"]: Creation complete after 5s [id=pve:vmbr108]
proxmox_virtual_environment_network_linux_bridge.vm_bridge_name["vmbr117"]: Creating...
proxmox_virtual_environment_network_linux_bridge.vm_bridge_name["vmbr117"]: Creation complete after 4s [id=pve:vmbr117]
proxmox_virtual_environment_network_linux_bridge.vm_bridge_name["vmbr105"]: Creating...
proxmox_virtual_environment_network_linux_bridge.vm_bridge_name["vmbr105"]: Creation complete after 5s [id=pve:vmbr105]
Apply complete! Resources: 19 added, 0 changed, 0 destroyed.

全てのLinux Brdigeが正常に作成され、エラーが出ないことが確認できました。

OMV: おきのどくですがWebサーバーの証明書は切れてしまいました

問題

概要

上司「おお 証明書基盤運用部門よ 証明書の期限を切らしてしまうとは なにごとじゃ!」

ある日 Webサーバーの証明書が 切れていることが 発覚した…。

証明書は 定期的に更新されるように していたはずだ。

先日 上司による命令で 無理くりWebサーバーのシステムを dockerコンテナシステムへ移行したことぐらいしか 心当たりがない。

上司「コンテナについては 再起動するのはいいが dockerのコンフィグファイルなどに 変更は入れないでくれ!」

前提条件

CAサーバーはstep-caをデーモン化して常駐
ACMEクライアントはacme.sh

制約

docker-compose.ymlファイルについて、追加、変更をしてはならない
初期状態
webサーバーの証明書が切れている

終了状態

Webサイトの証明書が更新、もしくは新しいものが登録され、TSL通信を行うことができる
その旨をopenssl s_clientコマンドで発行した証明書が確認できる
確認した内容を報告書に記載すること

感想

step-caとacme.sh今回初めて知ったので、基本的なコマンドの使い方などでちょっと時間がかかってしまいました。
証明書周りの知識が増えたのでよかったです。
ただ、この問題自体は実際にDocker移行すると起こりそうな問題だなぁと思ったので、今後似たような場面で参考になりそうです。

補足

OMV-1でstep-caサーバーが起動しており、OMV-2からacme.shを実行しています。

解答

今回はDockerに移行したことにより、80/443ポートが占有されているのでacme.shのstandaloneモードでの証明書検証ができなくなり、証明書の期限が切れたと考えられます。

standaloneではなく、webrootでの検証に切り替えることで解決できました。

  1. step-caサーバーでbob.internalが解決できるようにする

OMV-1で/etc/hostsに以下の行を追加して、bob.internalが解決できるようにします。

192.168.35.2 bob.internal
  1. nginxの設定を変更して、検証で利用するファイルにアクセスできるようにする。

OMV-2にて、/home/user/nginx/conf.d/default.confに以下の設定を追加します。

server {
 listen 443 ssl;
 server_name localhost;
+    location ^~ /.well-known/acme-challenge/ {
+        root /usr/share/nginx/html;
+        satisfy any;
+        allow all;
+    }

変更後はホームディレクトリで、sudo docker compose restartを実行してnginxを再起動します。

  1. 証明書を更新します
    OMV-2にて、以下のコマンドを実行して証明書を更新します。
user@OMV-2:~/.acme.sh$  ~/.acme.sh/acme.sh --insecure --server https://192.168.35.1:8443/acme/acme/directory --issue --webroot /opt/web -d bob.internal
[Sun Mar 16 14:10:14 JST 2025] Using CA: https://192.168.35.1:8443/acme/acme/directory
[Sun Mar 16 14:10:14 JST 2025] Single domain='bob.internal'
[Sun Mar 16 14:10:14 JST 2025] Getting webroot for domain='bob.internal'
[Sun Mar 16 14:10:15 JST 2025] Verifying: bob.internal
[Sun Mar 16 14:10:15 JST 2025] Success
[Sun Mar 16 14:10:15 JST 2025] Verification finished, beginning signing.
[Sun Mar 16 14:10:15 JST 2025] Let's finalize the order.
[Sun Mar 16 14:10:15 JST 2025] Le_OrderFinalize='https://192.168.35.1:8443/acme/acme/order/RXym3b56BhqqXJDY8ZYbbQTLcSWaPwqf/finalize'
[Sun Mar 16 14:10:15 JST 2025] Downloading cert.
[Sun Mar 16 14:10:15 JST 2025] Le_LinkCert='https://192.168.35.1:8443/acme/acme/certificate/yfrfE46Urhlc5dTW7KwFyZWXirY8UMuw'
[Sun Mar 16 14:10:15 JST 2025] Cert success.
-----BEGIN CERTIFICATE-----
MIIB8jCCAZegAwIBAgIRAOIEKmxEdrPcwo9YGVw5yawwCgYIKoZIzj0EAwIwMDEO
MAwGA1UEChMFaWN0c2MxHjAcBgNVBAMTFWljdHNjIEludGVybWVkaWF0ZSBDQTAe
Fw0yNTAzMTYwNTA5MTRaFw0yNTAzMTcwNTEwMTRaMBcxFTATBgNVBAMTDGJvYi5p
bnRlcm5hbDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABPxUo5o7PF2/lzDa6zoV
sdPHdbPWsvI/hjwOYOXvjqsBgoeZHd3FY0MORqvCSpuSXW3KDJxl9Y2CobU48QJI
NKijgaowgacwDgYDVR0PAQH/BAQDAgeAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggr
BgEFBQcDAjAdBgNVHQ4EFgQUqz73QJZ2qgaWJ7mwvy0hskw87BgwHwYDVR0jBBgw
FoAUaeM8uQQVTSYGXXDp7b7PSplX7GIwFwYDVR0RBBAwDoIMYm9iLmludGVybmFs
MB0GDCsGAQQBgqRkxihAAQQNMAsCAQYEBGFjbWUEADAKBggqhkjOPQQDAgNJADBG
AiEAz9y+eay3VqhtThEPInawW3zLj3I76InX9zGA6ff5hagCIQDQh6r2r0GIFNdM
naPFVzvZVYW7CzGrx+1rky3MZKlt/g==
-----END CERTIFICATE-----
[Sun Mar 16 14:10:15 JST 2025] Your cert is in: /home/user/.acme.sh/bob.internal_ecc/bob.internal.cer
[Sun Mar 16 14:10:15 JST 2025] Your cert key is in: /home/user/.acme.sh/bob.internal_ecc/bob.internal.key
[Sun Mar 16 14:10:15 JST 2025] The intermediate CA cert is in: /home/user/.acme.sh/bob.internal_ecc/ca.cer
[Sun Mar 16 14:10:15 JST 2025] And the full-chain cert is in: /home/user/.acme.sh/bob.internal_ecc/fullchain.cer
  1. 作成した証明書をNginxでマウントしているディレクトリにコピーします
sudo cp /home/user/.acme.sh/bob.internal_ecc/bob.internal.key /usr/local/share/ca-certificates/bob.internal.key
sudo cp /home/user/.acme.sh/bob.internal_ecc/fullchain.cer /usr/local/share/ca-certificates/fullchain.cer

コピーした後に再度ホームディレクトリで、sudo docker compose restartを実行してnginxを再起動します。

OMV-1で接続して、証明書の有効期限が切れていないことを確認します。

user@OMV-1:~$ echo | openssl s_client -connect 192.168.35.2:443 2>/dev/null | openssl x509 -noout -text
Certificate:
 Data:
     Version: 3 (0x2)
     Serial Number:
         e2:04:2a:6c:44:76:b3:dc:c2:8f:58:19:5c:39:c9:ac
     Signature Algorithm: ecdsa-with-SHA256
     Issuer: O = ictsc, CN = ictsc Intermediate CA
     Validity
         Not Before: Mar 16 05:09:14 2025 GMT
         Not After : Mar 17 05:10:14 2025 GMT
     Subject: CN = bob.internal
     Subject Public Key Info:
         Public Key Algorithm: id-ecPublicKey
             Public-Key: (256 bit)
             pub:
                 04:fc:54:a3:9a:3b:3c:5d:bf:97:30:da:eb:3a:15:
                 b1:d3:c7:75:b3:d6:b2:f2:3f:86:3c:0e:60:e5:ef:
                 8e:ab:01:82:87:99:1d:dd:c5:63:43:0e:46:ab:c2:
                 4a:9b:92:5d:6d:ca:0c:9c:65:f5:8d:82:a1:b5:38:
                 f1:02:48:34:a8
             ASN1 OID: prime256v1
             NIST CURVE: P-256
     X509v3 extensions:
         X509v3 Key Usage: critical
             Digital Signature
         X509v3 Extended Key Usage: 
             TLS Web Server Authentication, TLS Web Client Authentication
         X509v3 Subject Key Identifier: 
             AB:3E:F7:40:96:76:AA:06:96:27:B9:B0:BF:2D:21:B2:4C:3C:EC:18
         X509v3 Authority Key Identifier: 
             69:E3:3C:B9:04:15:4D:26:06:5D:70:E9:ED:BE:CF:4A:99:57:EC:62
         X509v3 Subject Alternative Name: 
             DNS:bob.internal
         1.3.6.1.4.1.37476.9000.64.1: 
             0......acme..
 Signature Algorithm: ecdsa-with-SHA256
 Signature Value:
     30:46:02:21:00:cf:dc:be:79:ac:b7:56:a8:6d:4e:11:0f:22:
     76:b0:5b:7c:cb:8f:72:3b:e8:89:d7:f7:31:80:e9:f7:f9:85:
     a8:02:21:00:d0:87:aa:f6:af:41:88:14:d7:4c:9d:a3:c5:57:
     3b:d9:55:85:bb:0b:31:ab:c7:ed:6b:93:2d:cc:64:a9:6d:fe

Not After : Mar 17 05:10:14 2025 GMTなので、証明書が有効期限内であると確認できました。

JKI: 証明書を二つも使っちゃいます!

問題

概要

社内ではプライベート認証局による自己証明書を用いた証明書基盤が構築されていました。

ある日、新しく社内の"carol.internal"というドメインに証明書を発行することになりました。

「あーあ、上司が新しいドメインに証明書発行しろしろってうるさいからコマンド打ってみるか」

「うちの証明書基盤がエラー出すわけねーよな」

「異常ねえや」

"Pending. The CA is processing your order, please wait."

前提条件

  • CAサーバーはstep-caをデーモン化したものが常駐
  • ACMEクライアントはacme.sh

初期状態

"carol.internal"に対して新しい証明書を発行できない

終了状態

  • "carol.internal"に対して新しい証明書を発行できる
  • opensslコマンドで発行した証明書が確認できる
    • 確認した内容を報告書に記載すること

補足

JKI-1でstep-caサービスが起動しており、JKI-2からacme.shを呼び出します。

感想

OMVで証明書周りの知識を得たので、似たような知識を使えそうなこの問題を担当しました。
OMVとほぼほぼ同じ方法だったのであってるのか若干不安です...
一応終了条件は満たしましたが、若干物足りないような気もしてます。

解答

今回の問題は、JKI-1がcarol.internalを解決できていないことと、JKI-2で特権ポートを利用してacmeが検証しようとしていてサーバーが起動していなかったことが原因だと考えられます。

以下の手順で解決できました。

  1. JKI-1で/etc/hostsを変更してcarol.internalを解決できるようにする
    sudo vim /etc/hostsで以下の行を追加します。
192.168.13.2 carol.internal
  1. JKI-2でiptablesを変更して、80ポートへの通信が8080ポートに届くようにします。
user@JKI-2:~$ sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080
  1. 最後にJKI-2で証明書を発行します。
user@JKI-2:~$ ~/.acme.sh/acme.sh --insecure --server https://192.168.13.1:8443/acme/acme/directory --issue --standalone -d carol.internal --httpport 8080
[Sun Mar 16 14:51:00 JST 2025] Using CA: https://192.168.13.1:8443/acme/acme/directory
[Sun Mar 16 14:51:00 JST 2025] Standalone mode.
[Sun Mar 16 14:51:00 JST 2025] Single domain='carol.internal'
[Sun Mar 16 14:51:01 JST 2025] Getting webroot for domain='carol.internal'
[Sun Mar 16 14:51:01 JST 2025] Verifying: carol.internal
[Sun Mar 16 14:51:01 JST 2025] Standalone mode server
[Sun Mar 16 14:51:03 JST 2025] Success
[Sun Mar 16 14:51:03 JST 2025] Verification finished, beginning signing.
[Sun Mar 16 14:51:03 JST 2025] Let's finalize the order.
[Sun Mar 16 14:51:04 JST 2025] Le_OrderFinalize='https://192.168.13.1:8443/acme/acme/order/B6DRKRX0m6mveieEKdCYwBuPHJrNYtUA/finalize'
[Sun Mar 16 14:51:04 JST 2025] Downloading cert.
[Sun Mar 16 14:51:04 JST 2025] Le_LinkCert='https://192.168.13.1:8443/acme/acme/certificate/K3WnQKhQgkGL26pcc8jjXJtBcxUoZECO'
[Sun Mar 16 14:51:04 JST 2025] Cert success.
-----BEGIN CERTIFICATE-----
MIIB9TCCAZqgAwIBAgIQDEYItVEZw5r5WQ57n2bCrTAKBggqhkjOPQQDAjAwMQ4w
DAYDVQQKEwVpY3RzYzEeMBwGA1UEAxMVaWN0c2MgSW50ZXJtZWRpYXRlIENBMB4X
DTI1MDMxNjA1NTAwMVoXDTI1MDMxNzA1NTEwMVowGTEXMBUGA1UEAxMOY2Fyb2wu
aW50ZXJuYWwwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAS7nd7XUJ9dYL9XrJnT
BnOFninqdwth5Wi0M0Doj1ihWsBAzpfHHsGCjn2KMh1e3zO4NCSfcsyyoFrbNVSV
2HAdo4GsMIGpMA4GA1UdDwEB/wQEAwIHgDAdBgNVHSUEFjAUBggrBgEFBQcDAQYI
KwYBBQUHAwIwHQYDVR0OBBYEFCvECRWwtDK9yoaLMTc06XaUHd/FMB8GA1UdIwQY
MBaAFKmvO9MYaNvepmi6NhPRB5BR0JUCMBkGA1UdEQQSMBCCDmNhcm9sLmludGVy
bmFsMB0GDCsGAQQBgqRkxihAAQQNMAsCAQYEBGFjbWUEADAKBggqhkjOPQQDAgNJ
ADBGAiEAu0/YO71vJ7NtpQema2WLf7aeXuxEOJ+kmeD2T4hxlmECIQCa2GfaXV8H
zLlKNidKqABEY95O5IaCF6D94Bi+gOvslg==
-----END CERTIFICATE-----
[Sun Mar 16 14:51:04 JST 2025] Your cert is in: /home/user/.acme.sh/carol.internal_ecc/carol.internal.cer
[Sun Mar 16 14:51:04 JST 2025] Your cert key is in: /home/user/.acme.sh/carol.internal_ecc/carol.internal.key
[Sun Mar 16 14:51:04 JST 2025] The intermediate CA cert is in: /home/user/.acme.sh/carol.internal_ecc/ca.cer
[Sun Mar 16 14:51:04 JST 2025] And the full-chain cert is in: /home/user/.acme.sh/carol.internal_ecc/fullchain.cer

発行された証明書を確認します。
有効な証明書が発行されていることが確認できました。

user@JKI-2:~$ openssl x509 -in /home/user/.acme.sh/carol.internal_ecc/carol.internal.cer -text -noout
Certificate:
 Data:
     Version: 3 (0x2)
     Serial Number:
         0c:46:08:b5:51:19:c3:9a:f9:59:0e:7b:9f:66:c2:ad
     Signature Algorithm: ecdsa-with-SHA256
     Issuer: O = ictsc, CN = ictsc Intermediate CA
     Validity
         Not Before: Mar 16 05:50:01 2025 GMT
         Not After : Mar 17 05:51:01 2025 GMT
     Subject: CN = carol.internal
     Subject Public Key Info:
         Public Key Algorithm: id-ecPublicKey
             Public-Key: (256 bit)
             pub:
                 04:bb:9d:de:d7:50:9f:5d:60:bf:57:ac:99:d3:06:
                 73:85:9e:29:ea:77:0b:61:e5:68:b4:33:40:e8:8f:
                 58:a1:5a:c0:40:ce:97:c7:1e:c1:82:8e:7d:8a:32:
                 1d:5e:df:33:b8:34:24:9f:72:cc:b2:a0:5a:db:35:
                 54:95:d8:70:1d
             ASN1 OID: prime256v1
             NIST CURVE: P-256
     X509v3 extensions:
         X509v3 Key Usage: critical
             Digital Signature
         X509v3 Extended Key Usage: 
             TLS Web Server Authentication, TLS Web Client Authentication
         X509v3 Subject Key Identifier: 
             2B:C4:09:15:B0:B4:32:BD:CA:86:8B:31:37:34:E9:76:94:1D:DF:C5
         X509v3 Authority Key Identifier: 
             A9:AF:3B:D3:18:68:DB:DE:A6:68:BA:36:13:D1:07:90:51:D0:95:02
         X509v3 Subject Alternative Name: 
             DNS:carol.internal
         1.3.6.1.4.1.37476.9000.64.1: 
             0......acme..
 Signature Algorithm: ecdsa-with-SHA256
 Signature Value:
     30:46:02:21:00:bb:4f:d8:3b:bd:6f:27:b3:6d:a5:07:a6:6b:
     65:8b:7f:b6:9e:5e:ec:44:38:9f:a4:99:e0:f6:4f:88:71:96:
     61:02:21:00:9a:d8:67:da:5d:5f:07:cc:b9:4a:36:27:4a:a8:
     00:44:63:de:4e:e4:86:82:17:a0:fd:e0:18:be:80:eb:ec:96

Discussion