Envoy Gateway を使って argocd-server に HTTPS でアクセスする
Table of Contents
1. はじめに
今回は、自宅の Kubernetes クラスターで、Kubernetes の Gateway API 実装の一つである Envoy Gateway を使って、argocd-server に HTTPS でアクセスできるようにするまでの手順を紹介します。
Argo CD のドキュメントには Ingress Configuration のページはあるのですが、Gateway API を使った設定方法は見当たらなかったため、色々と試行錯誤しながらやってみました。
2. Argo CDについて
まずは Argo CD について簡単に紹介します。
Argo CD は、Kubernetes クラスター上で GitOps を実践するための CD (Continuous Delivery) ツールです。 Git リポジトリを SSOT (Single Source of Truth) として、宣言的かつ自動的な Kubernetes リソースの管理ができます。
From https://argo-cd.readthedocs.io/en/stable/#architecture
例えば以下のような画面で登録した Application の状態を確認したり、Git リポジトリとの同期操作を行ったりできます。
From https://argo-cd.readthedocs.io/en/stable/#what-is-argo-cd
Argo CD は複数のコンポーネントで構成されており、今回 HTTPS でアクセスできるようにする argocd-server は、先ほど見せた Web UI と API エンドポイントを提供するコンポーネントです。
今回はこの argocd-server に、Envoy Gateway を通して HTTPS でセキュアにアクセスできるようにすることを目指してやっていきます。
3. Envoy Gatewayについて
Envoy Gateway は、Envoy Proxy を利用した Kubernetes の Gateway API 実装の一つです。
From https://gateway.envoyproxy.io/docs/
Gateway API は、Kubernetes ネイティブな方法でロードバランシングやトラフィック管理を行うための標準的な API 仕様で、従来の Ingress リソースに比べてより柔軟で拡張性の高い設計をすることができます。 基本的に新規で作成するなら Gateway API を使うのがいい(はず?)です。
Envoy Gateway を使うことで Kubernetes クラスター内外のトラフィックを制御することができ、クラスタ外から Service にアクセスするためのロードバランサとして機能させることもできます。 Gateway API は当然 Kubernetes リソースのため、それらの制御はすべて YAML マニフェストだけで行うことができるのも嬉しいポイントです。
4. 環境構成
今回の環境はこんな感じです。
- Kubernetes クラスター: 自宅サーバー上の環境(kubeadm + OVN-Kubernetes)
- Envoy Gateway: v1.5.0
- Argo CD: v3.0.16
- 証明書: CA/Server 証明書を Ansible で作成して Kubernetes Secret に登録
Kubernetes クラスターについてはこちらの記事で構築方法を紹介していますので、興味があればぜひそちらもご覧ください。
5. インストール手順
5.1 Argo CDのインストール
Argo CD のインストールは基本的に 公式ドキュメント 通りにやりますが、マニフェストの管理は kustomize で行いました。
kustomize/argocd/
├── kustomization.yaml
├── namespace.yaml
├── patch-argocd-cmd-params-cm.yaml
└── http-route.yaml
TLS 終端は Envoy Gateway で行うため、patch-argocd-cmd-params-cm.yaml
では argocd-server が insecure モードで起動して HTTP だけリッスンするように設定します。
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-cmd-params-cm
data:
server.insecure: "true"
こちらの設定についても 公式ドキュメント に説明があり、server.xxx
の形式で ConfigMap に書いたものが argocd-server
の起動オプションとして渡されます。
The commands can also be configured by setting the respective flag of the available options in argocd-cmd-params-cm.yaml. Each component has a specific prefix associated with it.
argocd-server --> server argocd-repo-server --> reposerver argocd-application-controller --> controller
基本的に Argo CD 自体のインストールは以上ですが、Gateway API の HTTPRoute リソースについては後ほど説明します。
5.2 Envoy Gatewayのインストール
Envoy Gateway 本体のインストールは先ほど作成した Argo CD を利用して行います。
筆者の環境では MetalLB の LoadBalancer が使えたため、
kubectl patch svc argocd-server -n argocd -p '{"spec": {"type": "LoadBalancer"}}'
のようにして一時的に argocd-server の Service にアクセスできるようにして Argo CD を利用しました。
Argo CD による Envoy Gateway のインストール手順は 公式ドキュメント に書いてあるものを参考にしています。
cat <<EOF | kubectl apply -f -
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: envoy-gateway
namespace: argocd
spec:
project: default
source:
chart: gateway-helm
repoURL: docker.io/envoyproxy
targetRevision: v1.5.0
destination:
namespace: envoy-gateway-system
server: https://kubernetes.default.svc
syncPolicy:
syncOptions:
- CreateNamespace=true
- ServerSideApply=true
automated:
prune: true
selfHeal: true
EOF
インストール後、Envoy Gateway のコンポーネントが起動していることを確認します。
$ kubectl -n envoy-gateway-system get pods
NAME READY STATUS RESTARTS AGE
envoy-gateway-5d4b5b9f4c-xyz12 1/1 Running 0 2m30s
これで Envoy Gateway 自体のインストールは完了です。 Gateway API のリソース作成は後ほど行います。
5.3 証明書の準備
HTTPS 接続のために Envoy Gateway が使うための CA/Server 証明書を Ansible で作成します。
CA 証明書の作成はこんな感じです。
# roles/cert/tasks/ca.yml
- name: Generate CA private key
community.crypto.openssl_privatekey:
path: "{{ cert.ca.key_path }}"
type: RSA
size: 4096
owner: root
group: root
mode: "0600"
- name: Generate CA certificate signing request
community.crypto.openssl_csr:
path: "{{ cert.ca.csr_path }}"
privatekey_path: "{{ cert.ca.key_path }}"
organization_name: "{{ cert.ca.organization_name }}"
common_name: "{{ cert.ca.common_name }}"
basic_constraints:
- "CA:TRUE"
basic_constraints_critical: true
key_usage:
- keyCertSign
- cRLSign
key_usage_critical: true
owner: root
group: root
mode: "0644"
- name: Generate CA certificate
community.crypto.x509_certificate:
path: "{{ cert.ca.cert_path }}"
privatekey_path: "{{ cert.ca.key_path }}"
csr_path: "{{ cert.ca.csr_path }}"
provider: selfsigned
selfsigned_not_after: "+{{ cert.ca.validity_days }}d"
owner: root
group: root
mode: "0644"
- name: Display CA certificate info
community.crypto.x509_certificate_info:
path: "{{ cert.ca.cert_path }}"
register: ca_cert_info
- name: Show CA certificate details
ansible.builtin.debug:
msg:
- "CA Certificate created successfully"
- "Subject: {{ ca_cert_info.subject }}"
- "Valid from: {{ ca_cert_info.not_before }}"
- "Valid until: {{ ca_cert_info.not_after }}"
- "Serial number: {{ ca_cert_info.serial_number }}"
必要最低限、common name と organization_name を指定し、鍵の作成 -> CSR の作成 -> CA 証明書の作成の順で実行しています。
Server 証明書もほとんど同じです。
# roles/cert/tasks/server.yml
- name: Generate server private key
community.crypto.openssl_privatekey:
path: "{{ cert.server.key_path }}"
size: 2048
type: RSA
owner: root
group: root
mode: "0600"
- name: Generate server certificate signing request
community.crypto.openssl_csr:
path: "{{ cert.server.csr_path }}"
privatekey_path: "{{ cert.server.key_path }}"
organization_name: "{{ cert.server.organization_name }}"
common_name: "{{ cert.server.common_name }}"
key_usage:
- digitalSignature
- keyEncipherment
extended_key_usage:
- serverAuth
- clientAuth
owner: root
group: root
mode: "0644"
- name: Generate server certificate signed by CA
community.crypto.x509_certificate:
path: "{{ cert.server.cert_path }}"
privatekey_path: "{{ cert.server.key_path }}"
csr_path: "{{ cert.server.csr_path }}"
provider: ownca
ownca_path: "{{ cert.ca.cert_path }}"
ownca_privatekey_path: "{{ cert.ca.key_path }}"
ownca_not_after: "+{{ cert.server.validity_days }}d"
owner: root
group: root
mode: "0644"
- name: Display server certificate info
community.crypto.x509_certificate_info:
path: "{{ cert.server.cert_path }}"
register: server_cert_info
- name: Show server certificate details
ansible.builtin.debug:
msg:
- "Server Certificate created successfully"
- "Subject: {{ server_cert_info.subject }}"
- "Valid from: {{ server_cert_info.not_before }}"
- "Valid until: {{ server_cert_info.not_after }}"
- "Serial number: {{ server_cert_info.serial_number }}"
- "Subject Alt Names: {{ server_cert_info.subject_alt_name | default(['None']) }}"
- name: Verify server certificate against CA
community.crypto.x509_certificate_info:
path: "{{ cert.server.cert_path }}"
valid_at:
today: "+0d"
register: server_cert_verification
- name: Show certificate verification result
ansible.builtin.debug:
msg: "Server certificate is {{ 'valid' if server_cert_verification.valid_at.today else 'invalid' }}"
署名には先ほど作成した CA 証明書を使っています。
このように作成した Server 証明書と鍵を、Kubernetes Secret に登録します。
- name: Read server certificate
ansible.builtin.slurp:
src: "{{ cert.server.cert_path }}"
register: server_cert_content
- name: Read server private key
ansible.builtin.slurp:
src: "{{ cert.server.key_path }}"
register: server_key_content
- name: Create TLS secret in Kubernetes
kubernetes.core.k8s:
api_version: v1
kind: Secret
name: "{{ k8s.secret_name }}"
namespace: "{{ k8s.namespace }}"
definition:
type: kubernetes.io/tls
data:
tls.crt: "{{ server_cert_content.content }}"
tls.key: "{{ server_key_content.content }}"
TLS secrets の書き方については Kubernetes のドキュメント に記載があります。
これらの Ansible Playbook を実行することで、Envoy Gateway 用の Server 証明書が Kubernetes Secret に登録されます。
$ kubectl get secret -n gateway-system
NAME TYPE DATA AGE
cert-home-tomokon-net kubernetes.io/tls 2 2m
もしかしたらこういうのって cert-manager とかを使った方が楽だったかもしれませんが、終わってから気づきました…
何はともあれ、作成した Server 証明書を信頼できるものと定義するためには、クライアント側(今回は macOS)に CA 証明書をインポートする必要があります。
こんな感じで CA 証明書として登録されており、“Trusted” になっていれば OK です。


ここまでで、Gateway API のリソースを作成する準備が整いました。 ここからは実際に Gateway API リソースの作成に入っていきます。
6. Gateway設定
6.1 GatewayClassの作成
GatewayClass は Gateway API におけるコントローラーの定義のクラスタリソースです。 どのコントローラー(今回は Envoy Gateway)が Gateway を管理するかを指定します。
IngressClass みたいなものだと思ってもらえれば大丈夫です。
# kustomize/gateway/gateway-class.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
name: envoy
spec:
controllerName: gateway.envoyproxy.io/gatewayclass-controller
GatewayClass はクラスター全体で共有されるリソースのため、namespace 指定は不要です。
6.2 Gatewayの作成
続いて先ほどの GatewayClass を使用して Gateway リソースを作成していきます。
Gateway は実際のロードバランサーを作成するためのリソースです。
今回はHTTPS(443ポート)で listen し、TLS 終端を行います。
また、特定のラベルがついた他の Namespace に存在する HTTPRoute リソースから参照できるように allowedRoutes
の設定をしています:
# kustomize/gateway/gateway.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: envoy-http
namespace: gateway-system
spec:
gatewayClassName: envoy
listeners:
- name: https
protocol: HTTPS
port: 443
hostname: "*.home.tomokon.net"
allowedRoutes:
namespaces:
from: Selector
selector:
matchLabels:
shared-gateway-access: "true"
tls:
mode: Terminate
certificateRefs:
- kind: Secret
group: ""
name: cert-home-tomokon-net
tls
のフィールドでは先ほど作成した Server 証明書を含む Secret を指定しています。
また、hostname: "*.home.tomokon.net"
のようにワイルドカードで指定することで、home.tomokon.net
のサブドメインを指定した xxxRoute リソースから紐付けられるようになります。
Gateway を作成すると、Envoy Gateway によって type: LoadBalancer
の Service が自動的に作成されるようです:
$ kubectl get svc -n envoy-gateway-system | hgrep -i loadbalancer
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
envoy-gateway-system-envoy-http-165ae7c4 LoadBalancer 10.96.181.180 192.168.1.151 443:30384/TCP 2d8h
6.3 HTTPRouteの作成
いよいよ HTTPRoute リソースの作成です。
HTTPRoute は特定のホスト名とパスを、バックエンドの Service にルーティングすることができます。 これによって argocd-server に指定したホスト名で、かつ HTTPS でアクセスできるようにします:
# kustomize/argocd/http-route.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: argocd-server
namespace: argocd
spec:
parentRefs:
- name: envoy-http
namespace: gateway-system
hostnames:
- "argocd.home.tomokon.net"
rules:
- backendRefs:
- name: argocd-server
port: 80
parentRefs
や hostnames
を見て自動的に先ほど作成した Gateway リソースと紐づけられますが、そのためには Gateway の allowedRoutes
で指定した条件を満たすために argocd Namespace に特定のラベルをつける必要があります:
apiVersion: v1
kind: Namespace
metadata:
name: argocd
labels:
name: argocd
shared-gateway-access: "true"
これで、argocd namespace の HTTPRoute が gateway-system の Gateway に紐付けられるようになります。
また、作成した HTTPRoute は argocd.home.tomokon.net
のホスト名でアクセスできるようにしているため、先ほど Gateway リソース作成時に払い出された Service type=LoadBalancer の EXTERNAL-IP に対して、DNS で argocd.home.tomokon.net
を解決できるように設定しておく必要があります。
筆者の環境では自宅サーバー上の DNS サーバーの BIND9 にレコードを追加しました。 DNS サーバーの構築については こちらの記事 で紹介していますので、興味があればぜひそちらもご覧ください。
$ dig argocd.home.tomokon.net +short
gateway.home.tomokon.net.
192.168.1.151
7. 動作確認
設定が完了したら、HTTPS でアクセスできることを確認します。
$ curl -I https://argocd.home.tomokon.net
HTTP/2 200
accept-ranges: bytes
content-length: 788
content-security-policy: frame-ancestors 'self';
content-type: text/html; charset=utf-8
vary: Accept-Encoding
x-frame-options: sameorigin
x-xss-protection: 1
date: Tue, 09 Sep 2025 14:17:19 GMT
ブラウザからも正常に Argo CD の Web UI にアクセスできることを確認しました。

8. まとめ
今回は自宅の Kubernetes クラスターで Envoy Gateway を使って Argo CD サーバーに HTTPS でアクセスする環境を構築しました!
Envoy Gateway は Gateway API の理解さえできれば割と素直に扱えて使いやすかったです。 今後も色んなアプリケーションをこの Gateway を通してアクセスできるようにしていきたいと思います。
最後まで読んでいただき、ありがとうございました!