Apache를 역전파로 사용한 Gitea SSL

k8s에서 컨테이너 레지스트리 사용을 위해서는 SSL을 사용해야 합니다.

Page content

우리는 안전하고 편리한 컨테이너 레지스트리 호스팅을 원합니다. 이 레지스트리에 도커 이미지를 푸시하고, 우리의 쿠버네티스 클러스터가 이 레지스트리에서 이미지를 풀어내도록 하려고 합니다. 그래서 우리는 SSL을 사용한 Gitea를 사용하는 아이디어가 떠올랐습니다.

  1. Gitea에는 이미 컨테이너 레지스트리가 포함되어 있습니다.
  2. TLS 종료 프록시로 Apache를 사용하여 Gitea에 HTTPS를 추가할 수 있습니다.
  3. 이것이 시작점이었습니다. 자가 서명된 인증서와 루트 CA를 생성하는 과정 등…

모든 레지스트리에는 자신의 비밀이 있습니다

쿠버네티스에서 레지스트리가 필요한 경우

불행히도 kubespray로 생성된 쿠버네티스 클러스터 내부의 레지스트리는 제게 작동하지 않습니다.

  • 이미지를 그 안에 푸시하려면 kube-proxy를 통해 임시 터널을 생성해야 합니다.
  • 이미지를 그 안에 푸시한 후에도, 현재 버전의 새 클러스터는 이 내부 레지스트리에서 이미지를 풀어내지 못했습니다.

두 밤을 멋진 시간을 보내며 문제를 해결하려고 시도한 후, 결국 Gitea의 내부 컨테이너 레지스트리를 사용하기로 결정했습니다. HTTPS로 이 레지스트리에 접근할 수 있도록 구성만 하면 됩니다.

어쨌든 이 레지스트리를 공개할 것이기 때문에, 도커와 쿠버네티스는 도커 로그인을 할 필요가 없습니다. 아마도. 어떻게 될지 보고 판단해 보겠습니다.

작동 여부를 테스트해 보기

컨테이너 레지스트리가 우리에게 적합한지 확인하기 위해 다음과 같은 작업이 가능해야 합니다:

  • 이미지를 그곳에 푸시할 수 있고
  • 그 이미지로부터 쿠버네티스에 배포를 생성할 수 있어야 합니다.
sudo docker pull alpine:3.12.0
sudo docker images
sudo docker tag a24bb4013296 localhost:5000/rg/alpine:version.3.12.0
sudo docker push localhost:5000/rg/alpine:version.3.12.0

이제 xed alp1.yaml 또는 nano alp1.yaml을 실행하여, 기분에 따라 선택하고

apiVersion: apps/v1
kind: Deployment
metadata:
  name: alp-registry-test
spec:
  replicas: 1
  selector:
    matchLabels:
      app: alp-registry-test
  template:
    metadata:
      labels:
        app: alp-registry-test
    spec:
      containers:
        - name: alpine-test
          image: localhost:5000/rg/lpine:version.3.12.0
      imagePullSecrets:
      - name: registry-secret

이 파일은 다운로드 가능합니다.
이 배포를 생성해 보겠습니다.

kubectl create -f alp1.yaml
kubectl get pods

kubectl describe po alp-registry-test-5f5cb94b97-njsp2
# 또는 생성된 pod 또는 생성되지 않은 pod를 확인합니다.

이 부분에 대해 저는 알고 있습니다.

      imagePullSecrets:
      - name: registry-secret 

registry-secret은 kubespray가 생성한 비밀의 이름입니다.

정리

kubectl delete -f alp1.yaml

방법

Gitea 사이트: https-setup에 많은 문서가 있습니다.

그리고 해당 페이지: https://docs.gitea.com/administration/reverse-proxies에도 있습니다.

단계 1 - Apache 설치 및 간단한 테스트 사이트 생성

Apache 설치

sudo apt install apache2

방화벽에 무엇이 있는지 확인

sudo ufw status

방화벽이 활성화되어 있다면, https를 통해 노출할 포트를 선택하고 허용해야 합니다.
기본 Apache 설정은 다음과 같습니다.

sudo ufw app list

다음과 같은 내용을 볼 수 있을 수 있습니다.

Available applications:
  Apache
  Apache Full
  Apache Secure
  OpenSSH

포트 443만 활성화하려면 다음을 실행합니다.

sudo ufw allow 'Apache Secure'

확인해 보겠습니다.

sudo systemctl status apache2

다음으로, Apache를 테스트하기 위한 간단한 가상 서버를 생성합니다.

sudo mkdir /var/www/reg.homelab
sudo chown -R $USER:$USER /var/www/reg.homelab
sudo chmod -R 755 /var/www/reg.homelab
sudo nano /var/www/reg.homelab/index.html

다음 내용을 입력합니다.

<html>
    <head>
        <title>Welcome to reg.homelab!</title>
    </head>
    <body>
        <h1>성공! reg.homelab 가상 호스트가 작동 중입니다!</h1>
    </body>
</html>

그 후

sudo nano /etc/apache2/sites-available/reg.homelab.conf

다음 내용을 입력합니다.

<VirtualHost *:3080>
    ServerAdmin webmaster@localhost
    ServerName reg.homelab
    ServerAlias www.reg.homelab
    DocumentRoot /var/www/reg.homelab
    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

기본 사이트를 비활성화하고, 이 사이트를 활성화한 후 상태를 확인합니다.

sudo a2ensite reg.homelab.conf
sudo a2dissite 000-default.conf
sudo apache2ctl configtest

다음과 같은 메시지가 표시되나요?

AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 127.0.1.1. Set the 'ServerName' directive globally to suppress this message

그 후

sudo nano /etc/apache2/apache2.conf

끝에 다음을 추가합니다.

ServerName reg.homelab

이것은 여전히 끝이 아닙니다! 이제 80 포트의 바인딩 시도를 제거해야 합니다.

sudo nano /etc/apache2/ports.conf

다음 내용을 입력합니다.

Listen 3030
...
Listen 443

이제

sudo systemctl restart apache2
sudo systemctl status apache2
journalctl -xeu apache2.service
curl localhost:3080

좋습니다! 이제 :3080로 이동해 보세요.

단계 2 - 이 사이트를 Gitea로 연결하는 비보안 리버스 프록시로 전환

sudo nano /etc/apache2/sites-available/reg.homelab.conf

다음 내용을 입력합니다.

<VirtualHost *:443>
    ServerAdmin webmaster@localhost
    ServerName reg.homelab
    ServerAlias www.reg.homelab
    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined
    ProxyPreserveHost On
    ProxyRequests off
    AllowEncodedSlashes NoDecode
    ProxyPass / http://localhost:3000/ nocanon
</VirtualHost>

일부 설정 테스트

sudo apache2ctl configtest

일부 Apache 모듈을 추가하고 Apache를 재시작합니다.

sudo a2enmod proxy proxy_http ssl
sudo systemctl restart apache2
sudo systemctl status apache2

좋습니다. 이제 다음으로 이동하거나 curl을 실행합니다.

# 여전히 http이지만 443 포트에서 작동합니다.
curl http://localhost:443
http://<Server_IP_Address>:443/

단계 3 - 자가 서명된 루트 CA 및 사이트 인증서

SweetHome-RootCA.

CANAME=MostImportant-RootCA

# 선택사항, 디렉토리 생성
mkdir $CANAME
cd $CANAME

# AES 암호화된 개인 키 생성
openssl genrsa -aes256 -out $CANAME.key 4096

# 인증서 생성, 1826일 = 5년
openssl req -x509 -new -nodes -key $CANAME.key -sha256 -days 1826 -out $CANAME.crt -subj '/CN=My Root CA/C=AT/ST=Vienna/L=Vienna/O=MyOrganisation'

# 서비스용 인증서 생성
MYCERT=reg.homelab
openssl req -new -nodes -out $MYCERT.csr -newkey rsa:4096 -keyout $MYCERT.key -subj '/CN=My Firewall/C=AT/ST=Vienna/L=Vienna/O=MyOrganisation'

# SAN 속성을 위한 v3 ext 파일 생성
cat > $MYCERT.v3.ext << EOF
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
subjectAltName = @alt_names

[alt_names]
DNS.1 = reg.homelablab
DNS.2 = gitea.homelablab
IP.1 = 192.168.0.10
IP.2 = 192.168.0.11
EOF

openssl x509 -req -in $MYCERT.csr -CA $CANAME.crt -CAkey $CANAME.key -CAcreateserial -out $MYCERT.crt -days 730 -sha256 -extfile $MYCERT.v3.ext
Gitea/레지스트리에 연결하는 기계에서

Linux에서 루트 인증서 등록:

sudo cp MostImportant-RootCA.crt /usr/local/share/ca-certificates
sudo update-ca-certificates

Windows에서 루트 인증서 등록:

  • MostImportant-RootCA.crt 파일을 더블클릭합니다.
  • 로컬 사용자에 추가합니다.
  • 신뢰할 수 있는 루트 CA를 선택합니다.
  • 비인증 인증서를 가져오는 것에 대해 경고가 표시되면 ‘예’를 클릭합니다.

Windows에서 git pull 시 다음과 같은 메시지가 나타나면

Unable to resolve "unable to get local issuer certificate...

git에 Windows 네트워킹 레이어를 사용하도록 지정할 수 있습니다.

git config --global http.sslbackend schannel

단계 4 - 자가 서명 인증서로 프록시 보안

https://httpd.apache.org/docs/2.4/ssl/ssl_howto.html

단계 3에서 인증서를 생성하지 않았다면, 자가 서명 인증서를 생성합니다.

sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
  -subj "/CN=reg.homelab" \
  -addext "subjectAltName = DNS:reg.homelab" \
  -keyout /etc/ssl/private/apache-selfsigned-reg.homelab.key \
  -out /etc/ssl/certs/apache-selfsigned-reg.homelab.crt

이전 단계에서 생성한 것을 사용할 수도 있습니다.

sudo cp reg.homelab.crt /etc/ssl/certs/apache-selfsigned-reg.homelab.crt
sudo cp reg.homelab.key /etc/ssl/private/apache-selfsigned-reg.homelab.key

다시 가상 호스트 설정 파일을 열고

sudo nano /etc/apache2/sites-available/reg.homelab.conf

아래에 인증서를 사용하는 SSL 섹션을 추가합니다.

<VirtualHost *:443>
   ServerAdmin webmaster@localhost
   ServerName reg.homelab
   ServerAlias www.reg.homelab
   ErrorLog ${APACHE_LOG_DIR}/error.log
   CustomLog ${APACHE_LOG_DIR}/access.log combined
   ProxyPreserveHost On
   ProxyRequests off
   AllowEncodedSlashes NoDecode
   ProxyPass / http://localhost:3000/ nocanon
    
   SSLEngine on
   SSLCertificateFile /etc/ssl/certs/apache-selfsigned-reg.homelab.crt
   SSLCertificateKeyFile /etc/ssl/private/apache-selfsigned-reg.homelab.key
</VirtualHost>

설정을 확인하고, 서버를 재시작한 후 상태를 확인하고, SSL을 통해 Gitea로 이동해 보세요.

sudo apache2ctl configtest
sudo systemctl restart apache2
sudo systemctl status apache2

# 이동: http://<Server_IP_Address>:443/
# 또는
curl -k -v https://localhost

브라우저는 자가 서명 인증서에 대해 경고를 표시합니다.

연결이 안전하지 않습니다
공격자가 reg.homelab에서 정보(예: 비밀번호, 메시지 또는 신용카드)를 훔치려고 시도할 수 있습니다. 자세히 알아보기
NET::ERR_CERT_AUTHORITY_INVALID

하지만 지금은 이 경고를 무시하고, Let’s Encrypt을 사용할 때까지 기다리겠습니다.

이제 쿠버네티스 테스트

DNS 설정

각 쿠버네티스 노드에서:

sudo nano /etc/hosts

다음 내용을 추가합니다.

192.168.18.200 gitea.homelab
192.168.18.200 reg.homelab

루트 CA

각 쿠버네티스 노드에서:

sudo cp SweetHome-RootCA.crt /usr/local/share/ca-certificates
sudo update-ca-certificates

이제 재시작합니다.

레지스트리 자격 증명을 사용한 비밀 생성

https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/

sudo docker login reg.homelab
kubectl create secret generic regcred --from-file=.dockerconfigjson=/home/rg/.docker/config.json --type=kubernetes.io/dockerconfigjson

또는

kubectl create secret docker-registry regcred --docker-server=your-registry-server --docker-username=your-name --docker-password=your-pword --docker-email=your-email

새 도커 이미지 및 쿠버네티스 배포

sudo docker pull alpine:3.12.0
sudo docker images
sudo docker tag a24bb4013296 reg.homelab/rg/alpine:version.3.12.0
sudo docker push reg.homelab/rg/alpine:version.3.12.0

이제 nano alp2.yaml을 실행합니다. 이 파일은 다운로드 가능합니다.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: alp-registry-test
spec:
  replicas: 1
  selector:
    matchLabels:
      app: alp-registry-test
  template:
    metadata:
      labels:
        app: alp-registry-test
    spec:
      containers:
        - name: alpine-test
          image: reg.homelab/rg/alpine:version.3.12.0
      imagePullSecrets:
      - name: regcred

이 파일은 다운로드 가능합니다.
이 배포를 생성해 보겠습니다.

kubectl create -f alp2.yaml
kubectl get pods
kubectl describe po alp...

정리

kubectl delete -f alp2.yaml

유용한 링크