opensslワンライナーではじめるプライベートCAと用途別証明書の作り方

※最低限、CNやsubjectAltNameは要件に応じて書き換えてください

```shell:CA用の鍵と証明書の作成
openssl req \
  -newkey rsa:2048 -nodes -subj "/C=JP/ST=Tokyo/L=Chiyoda-ku/O=ACME, Inc./CN=rootca"  \
  -keyout ca.key | \
    openssl x509 -req -signkey ca.key \
      -days 10000 -extensions myreqexts -extfile <(printf "[myreqexts]\nkeyUsage=cRLSign,digitalSignature,keyCertSign
basicConstraints=CA:TRUE") \
      -out ca.crt

# 確認

openssl x509 -in ca.crt -text -noout
```

```shell:サーバ認証用の鍵と証明書の作成
openssl req \
  -newkey rsa:2048 -nodes -subj "/C=JP/ST=Tokyo/L=Chiyoda-ku/O=ACME, Inc./CN=servername"  \
  -keyout server.key | \
    openssl x509 -req -CA ca.crt -CAkey ca.key -CAcreateserial \
      -days 10000 -extensions myreqexts -extfile <(printf "[myreqexts]
subjectAltName=DNS:servername,DNS:www.example.com
keyUsage=digitalSignature,keyEncipherment
extendedKeyUsage=serverAuth") \
      -out server.crt

# 確認

openssl x509 -in server.crt -text -noout
```


```shell:クライアント認証用の鍵と証明書の作成
openssl req \
  -newkey rsa:2048 -nodes -subj "/C=JP/ST=Tokyo/L=Chiyoda-ku/O=ACME, Inc./CN=clientname"  \
  -keyout client.key | \
    openssl x509 -req -CA ca.crt -CAkey ca.key -CAcreateserial \
      -days 10000 -extensions myreqexts -extfile <(printf "[myreqexts]
subjectAltName=DNS:servername,DNS:www.example.com
keyUsage=digitalSignature,keyEncipherment
extendedKeyUsage=clientAuth") \
      -out client.crt

# 確認

openssl x509 -in client.crt -text -noout
```


```shell:Kubernetesクライアント証明書認証用の証明書作成
# Also see https://kubernetes.io/docs/reference/access-authn-authz/authentication/#x509-client-certs

openssl req \
  -newkey rsa:2048 -nodes -subj "/CN=user/O=group1/O=group2"  \
  -keyout user.key | \
    openssl x509 -req -CA ca.crt -CAkey ca.key -CAcreateserial \
      -days 10000 \
      -out user.crt

# 確認

openssl x509 -in user.crt -text -noout
```

# あとがき

たまにopensslでオレオレCAや自己署名証明書をつくる機会があるのですが、そのたびに忘れてググっているので改めて調べてみました。

よく見かける方法だと、CAは以下のような2ステップが必要になります。

- 鍵作成
- 証明書作成

サーバ証明書は以下のような3ステップが必要になります

- 鍵作成
- CSR作成
- 証明書作成

CAについては、鍵と証明書をまとめて発行するために以下のようなコマンドが紹介されている場合もありますが、これだと openssl バージョンによってはextensionsが証明書に設定されない場合があるようです。

```shell:よくみかけるCAの作り方(extensionsが設定されない)
openssl req -x509 -new \
  -nodes -newkey rsa:2048 -subj "/CN=rootca" -days 10000 \
  -config <(printf "
[req]
distinguished_name=distinguished_name
req_extensions=req_extensions

[distinguished_name]
C = US
ST = VA
L = SomeCity
O = MyCompany
OU = MyDivision
CN = www.company.com

[req_extensions]
keyUsage = cRLSign, digitalSignature, keyCertSign
extendedKeyUsage = serverAuth
basicConstraints = CA:TRUE
") \
  -keyout ca.key -out ca.crt

# 確認

openssl x509 -in ca.crt -ext keyUsage -text -noout
#=> "No extensions in certificate" エラー
```

また、サーバ証明書用だと以下のようなkey作成を-newkeyで省略した2ステップ版もよくみますね

```shell:2ステップでサーバ証明書の作成
# サーバ用のCSRの作成
openssl req \
  -newkey rsa:2048 -nodes -keyout server.key -subj "/CN=servername" -days 10000 -reqexts myreqexts -config <(cat /etc/ssl/openssl.cnf <(printf "\n[myreqexts]\nsubjectAltName=DNS:servername,DNS:www.example.com")) \
  -out server.csr

#サーバ証明書の作成
openssl x509 \
  -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -days 10000 -extensions myreqexts -extfile <(printf "[myreqexts]\nsubjectAltName=DNS:servername,DNS:www.example.com") \
  -out server.crt
```

こちらはCAを作る場合と比べてなにか問題があるというわけではないと思いますが、今回紹介した `openssl req` と `openssl x509` を組み合わせたワンラインナーだと、証明書の用途によらず同じような方法で済むため、わかりやすいのではないかと思います。