레이블이 openssl인 게시물을 표시합니다. 모든 게시물 표시
레이블이 openssl인 게시물을 표시합니다. 모든 게시물 표시

k8s ValidatingWebhookConfiguration 으로 문법 에러 ingress 리소스 생성 방지

# kubectl 과 같은 api 요청을 받는 k8s 서버는 kube-api handler 이후 요청한 리소스에 대해 mutating(리소스 변경),validating(리소스 검증) admission(허용 여부 판단 webhook) 처리를 하여 실제 리소스 설정(etcd 에 저장)될지 말지를 처리한다.

# nginx 에 적용될 server-snippet 등에 문법이 에러가 있는 ingress (리소스)를 적용 요청을 하면 에러 없이 리소스가 생성(등록)되는게 문제다.
kubectl apply -f syntax_error_ingress.yaml
ingress.extensions/ysoftman-test-ingress created

# nginx log 확인해 보면 에러 ingress 리소스 로드 시도가 계속 실패
kubectl logs -f $(kubectl get pod -n ingress-nginx | rg -N ingress-nginx-controller --color never  | awk '{print $1}')
 -------------------------------------------------------------------------------
Error: exit status 1
2021/12/22 17:19:34 [emerg] 15035#15035: invalid number of arguments in "proxy_set_header" directive in /tmp/nginx-cfg062794518:1076
nginx: [emerg] invalid number of arguments in "proxy_set_header" directive in /tmp/nginx-cfg062794518:1076
nginx: configuration file /tmp/nginx-cfg062794518 test failed
-------------------------------------------------------------------------------
W1222 17:19:34.507544       7 queue.go:130] requeuing ysoftman-test/ysoftman-test-ingress, err
-------------------------------------------------------------------------------

# 잘못된 ingress 리소스가 등록되어 계속 nginx 가 리로딩 실패해 문제가 되니 바로 지우자.
kubectl delete -f syntax_error_ingress.yaml

# 잘못된 설정으로 ingress-nginx-controller 가 전체에 영향 주는것을 막기 위해
# validating admission webhook server 를 옵션으로 노출할 수 있다.
# ValidatingWebhookConfiguration 리소스를 등록한다.


#####


# ValidatingWebhookConfiguration 으로 문법 에러 ingress 리소스 생성 방지하기

# (minikube 기준) kube-apiserver enable-admission-plugins 옵션에 ValidatingAdmissionWebhook 가 있는지 확인
kubectl get pod kube-apiserver-minikube -o=json -n kube-system | jq '.spec.containers[0].command' | rg -N "enable-admission-plugins"
  "--enable-admission-plugins=NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,ResourceQuota",

# ValidatingAdmissionWebhook 보이지 않아도 디폴트로 추가되어 있어 별도로 추가하지 않아도 된다.
# master 노드(장비) 마다 접속해 다음 파일에서
# --enable-admission-plugins 값을 추가하면
# kubelet(cluster의 모든 노드에 떠있는 agent)이 변경을 감지해 kube-apiserver(pod)가 자동으로 재시작 된다.
sudo vi /etc/kubernetes/manifests/kube-apiserver.yaml


# 방법1 - helm 으로 설치하면 ValidatingWebhookConfiguration 관련 리소스들이 자동 설치된다.


# 방법2 - ValidatingWebhookConfiguration 수동 등록
# 다음 명령 결과가 있다면 admission controller 를 사용할 수 있다.
# k8s 버전에 따라 
# k8s 1.6 이후는 admissionregistration.k8s.io/v1
# k8s 1.9 이후는 admissionregistration.k8s.io/v1beta1
kubectl api-versions | grep admissionregistration

# ingress-nginx-controller 버전 확인
kubectl get daemonset ingress-nginx-controller -n ingress-nginx -o=json | jq '.spec.template.spec.containers[0].image'
"quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.25.1"

# ValidatingWebhookConfiguration 은 TLS 로 통신해야 한다.
# 다음과 같이 self-singed 로 키를 생성한다.
# service 에서 사용할 이름이 매칭될 수 있도록 CN을 다음과 같이 설정한다. (CN=${SERVICE_NAME}.${NAMESPACE}.svc)
openssl req -x509 -newkey rsa:2048 -keyout validating-webhook-key.pem -out validating-webhook-cert.pem -days 100000 -nodes -subj "/CN=ingress-nginx-controller-admission.ingress-nginx.svc"

# secret 리소스를 등록하자.(base64 인코딩돼 등록되기 때문에 secret 리소스를 보면 LS0... 으로 시작하는 문자열이 된다.)
kubectl create secret tls ingress-validation-tls -n ingress-nginx \
--key validating-webhook-key.pem \
--cert validating-webhook-cert.pem

# ingress-nginx-controller 옵션 --validating-webhook 옵션들 추가
# secret 는 volumes, volumeMounts 로 pod 에서 파일로 접근하도록 한다.
kubectl edit daemonset ingress-nginx-controller -n ingress-nginx
... 생략 ...
      containers:
      - args:
        - /nginx-ingress-controller
        - --enable-ssl-chain-completion=false
        - --configmap=$(POD_NAMESPACE)/ingress-nginx
        - --tcp-services-configmap=$(POD_NAMESPACE)/tcp-services
        - --udp-services-configmap=$(POD_NAMESPACE)/udp-services
        - --annotations-prefix=nginx.ingress.kubernetes.io
        - --default-backend-service=default/default-backend-service
        - --report-node-internal-ip-address
        - --validating-webhook=:8443
        - --validating-webhook-certificate=/usr/local/certificates/tls.crt
        - --validating-webhook-key=/usr/local/certificates/tls.key
... 생략 ...
        ports:
        - containerPort: 8443
          name: webhook
          protocol: tcp
... 생략 ...
          volumeMounts:
          - name: webhook-cert
            mountPath: /usr/local/certificates/
            readOnly: true
... 생략 ...
      volumes:
      - name: webhook-cert
        secret:
          secretName: ingress-validation-tls

# ValidatingWebhookConfiguration 과 ingress-nginx-controller-admission service 리소스 등록은 아래 URL에 정리


#####


# 참고 이슈(삽질 엄청함ㅠ)
# 위의 모든 설정을 했는데 invalid ingress 가 아무런 제약없이 created 된다.
# ingrss nginx controller pod 로그를 보면 validationwebhook 은 동작되지만
kubectl logs -f $(kubectl get pod -n ingress-nginx | rg -N ingress-nginx-controller --color never  | awk '{print $1}') | rg "admission" -C 2

# 다음 로그 처럼 accepting 되는 문제가 있었다.
server.go:61] handling admission controller request /extensions/v1beta1/ingress?timeout=10s
main.go:87] accepting non ingress  in namespace ysoftman-test-namespace extensions/v1beta1, Resource=ingresses

# 나와 같이 nginx-ingress-controller:0.25.1 에서
# extensions/v1beta1 를 사용하지 못하는 문제가 있었다.

# syntax_error_ingress apiVersion 을 다음과 같이 변경
extensions/v1beta1 --> networking.k8s.io/v1beta1

# ValidatingWebhookConfiguration 에 networking.k8s.io/v1beta api 추가
  - apiGroups:
    - networking.k8s.io
    - extensions
    apiVersions:
    - v1
    - v1beta1
... 생략 ...
      path: /networking.k8s.io/v1beta1/ingresses

# 이제 server_snippnet 오타가 있는 ingress 등록시 에러가 발생하고 생성되지 않는다.
kubectl apply -f syntax_error_ingress.yaml
namespace/ysoftman-test-namespace unchanged
Error from server: error when creating "syntax_error_ingress.yaml": admission webhook "validate.nginx.ingress.kubernetes.io" denied the request:
-------------------------------------------------------------------------------
Error: exit status 1
2021/12/28 19:11:31 [emerg] 1385#1385: unexpected "}" in /tmp/nginx-cfg650933801:19967
nginx: [emerg] unexpected "}" in /tmp/nginx-cfg650933801:19967
nginx: configuration file /tmp/nginx-cfg650933801 test failed

golang https 인증서 사용

# golang 에서는 다음과 같이 인증서 및 키 파일을 이용해 https 를 사용 한다.
go func() {
  if err := http.ListenAndServeTLS(":443", "server.cert", "server.key", myhandler); err != nil {
  log.Fatal(err)
  }
}()

# 키 파일에 암호가 적용된 경우 다음과 같이 파싱 에러가 발생한다.
tls: failed to parse private key


# 따라서 다음과 같이 키파일에서 암호를 제거한 키파일을 만들어 사용해야 한다.
openssl rsa -in server.key -out nopassword_server.key
Enter pass phrase for key.key: 암호입력
writing RSA key

Apache httpd 에서 https http2 brotli 사용하기

# 2019-07-16 최신 버전 기준으로 내용 수정
# HTTP 2 는 기존 HTTP 1.x 의 비효율적인 속도를 개선한 버전으로 Multiplexed Strem, Header Compression 등의 기술이 포함되어 있다.
# 참고
# http://www.bloter.net/archives/210122
# https://icing.github.io/mod_h2/howto.html
# http://httpd.apache.org/docs/trunk/new_features_2_4.html
# http://httpd.apache.org/docs/2.4/programs/configure.html#installationdirectories

# apr 설치
wget http://apache.mirror.cdnetworks.com/apr/apr-1.7.0.tar.gz
tar zxvf apr-1.7.0.tar.gz
cd apr-1.7.0
./configure --prefix=${HOME}/apr
make -j8 && make install

# apr-util 설치
wget http://apache.mirror.cdnetworks.com//apr/apr-util-1.6.1.tar.gz
tar zxvf apr-util-1.6.1.tar.gz
cd apr-util-1.6.1
./configure --prefix=${HOME}/apr-util --with-apr=${HOME}/apr --with-crypto
make -j8 && make install

# openssl 설치
wget https://github.com/openssl/openssl/archive/OpenSSL_1_1_1c.tar.gz
tar zxvf OpenSSL_1_1_1c.tar.gz
cd openssl-OpenSSL_1_1_1c
./config --prefix=${HOME}/openssl -fPIC
make -j8 && make install

# nghttp2 설치
# 아파치 httpd 에서는 mod_http2 모듈을 로딩하여 HTTP 2 처리를 하게 된다.
# 자세한 내용은 https://httpd.apache.org/docs/2.4/mod/mod_http2.html
wget https://github.com/nghttp2/nghttp2/releases/download/v1.39.1/nghttp2-1.39.1.tar.gz
tar zxvf nghttp2-1.39.1.tar.gz
cd nghttp2-1.39.1
./configure --prefix=${HOME}/nghttp2 OPENSSL_CFLAGS="-I${HOME}/openssl/include" OPENSSL_LIBS="-L${HOME}/openssl/lib -lssl -lcrypto"
make -j8 && make install

# brotli 설치
# gzip 보다 향상된 압축방식이다.
# cmake 로 빌드하기 때문에 없으면 설치하자.
sudo yum install cmake
wget https://github.com/google/brotli/archive/v1.0.7.tar.gz
tar zxvf v1.0.7.tar.gz
cd brotli-1.0.7

# 빌드 결과물이 현재 위치에 생성되기 때문에 out 디렉토리를 생성하고 빌드하자.
mkdir -p out
cd out
../configure-cmake --prefix=${HOME}/brotli
make -j8 && make install

# httpd 설치
# 아파치 httpd 2.4.17 (부터 http2 지원) 이후 버전을 설치하자.
wget http://apache.tt.co.kr//httpd/httpd-2.4.39.tar.gz
tar zxvf httpd-2.4.39.tar.gz
cd httpd-2.4.39
./configure \
--prefix=${HOME}/apache-httpd \
--with-apr=${HOME}/apr \
--with-apr-util=${HOME}/apr-util \
--enable-brotli \
--with-brotli=${HOME}/brotli \
--enable-http2 \
--with-nghttp2=${HOME}/nghttp2 \
--enable-ssl \
--with-ssl=${HOME}/openssl \
--with-mpm=prefork \
--enable-mods-shared="unixd authz_core authz_user rewrite authz_host include log_config mime_magic headers unique_id setenvif mime status dir alias"
make -j8 && make install

# 참고
# apr, apr-util 소스를 별도로 빌드하지 않고
# httpd/srclib/apr, httpd/srclib/apr-util 이름으로 압축을 해제하면
# --with-apr --with-apr-util 옵션을 사용하지 않고 httpd 빌드할 수 있다.
# libapreq 설치
wget http://mirror.apache-kr.org//httpd/libapreq/libapreq2-2.13.tar.gz
tar zxvf libapreq2-2.13.tar.gz
cd libapreq2-2.13
./configure --with-apache2-apxs=${HOME}/apache-httpd/bin/apxs

# ${HOME}/apache-httpd/modules/mod_apreq2.so 로 설치된다.
make -j8 && make install

# http2 를 사용할 수 있도록 설정파일에 다음을 추가한다.
sudo vi conf/httpd.config
LoadModule http2_module modules/mod_http2.so
<IfModule http2_module>
LogLevel http2:info
</IfModule>

# h2 -> TLS(SSL) https 로 요청되는 경우
# h2c -> http 로 요청되는 경우
Protocols h2 h2c http/1.1

# 아파치 httpd 시작시 nghttpd 라이브러리를 참조할 수 있도록 환경변수 스크립트 수정
# 기존 경로에 openssl 과 nghttp2 를 추가해 준다.
vi ${HOME}/apache-httpd/bin/envvars
LD_LIBRARY_PATH="${HOME}/apache-httpd/lib:${HOME}/openssl/lib:${HOME}/nghttp2/lib:$LD_LIBRARY_PATH"
export LD_LIBRARY_PATH

# brotli 설정 추가
sudo vi conf/httpd.config
LoadModule brotli_module modules/mod_brotli.so
SetOutputFilter BROTLI_COMPRESS

# 아파치 httpd 시작~
sudo ${HOME}/apache-httpd/bin/apachectl -k start

# gzip brotli 압축 사용시 사이즈 보기
curl -H "Accept-Encoding: gzip" -o out.gz https://ysoftman.com/test
curl -H "Accept-Encoding: br" -o out.br https://ysoftman.com/test

# gzip 압축해제
gzip -d -k out.gz

# brotli 압축해제
# brew install brotli 설치
# https://github.com/google/brotli/blob/master/c/tools/brotli.md

Linux NginX 설치 및 빌드

# 참고
# http://wiki.nginx.org/Install
# http://wiki.nginx.org/CommandLine
# yum 으로 설치하는 경우
# CentOS 에서 yum 으로 설치할 경우 yum repository 정보를 추가
sudo vi /etc/yum.repos.d/nginx.repo
[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/centos/$releasever/$basearch/gpgcheck=0
enabled=1

# 설치
sudo yum install nginx

# nginx 설정 참고 /etc/nginx/sites-available/default
sudo vi /etc/nginx/conf.d/default.conf server{
    listen       80;
    server_name  localhost;
    root /home/ysoftman;
    index ysoftman.html;
    location /status {
            stub_status on;
            access_log off;
            allow all;
    }
    location /test{
    }}

# 경로에 대한 권한 확인
namei -m /home/ysoftman/test/ysoftman.html

# 권한이 없으면 설정
chmod 755 /home
chmod 755 /home/ysoftman
chmod 755 /home/ysoftman/test
chmod 744 ysoftman.html

# nginx 시작
sudo /etc/init.d/nginx start

# nginx 정지
sudo /etc/init.d/nginx stop

####################

# 소스 빌드해서 설치하는 경우
# 다운로드
wget http://nginx.org/download/nginx-1.12.0.tar.gz

# 압축 해제
tar zxvf nginx-1.12.0.tar.gz
cd nginx-1.12.0

# nginx 에 필요한 모듈 설치
sudo yum install pcre-devel
sudo yum install openssl-devel

# configure 수행 및 빌드 및 설치
# 별도의 openssl 사용시 옵션 --with-openssl=경로
./configure --prefix=/home/ysoftman/nginx --with-http_ssl_module --with-http_v2_module --with-http_stub_status_module
make
sudo make install

# nginx 설정
vi /home/ysoftman/nginx/conf/nginx.conf

# nginx 시작
sudo /home/ysoftman/nginx/sbin/nginx

# nginx 재시작
sudo /home/ysoftman/nginx/sbin/nginx -s reload

# nginx 정지
sudo /home/ysoftman/nginx/sbin/nginx -s stop

# nginx 설명
sudo /home/ysoftman/nginx/sbin/nginx -h

OpenSSL 빌드 및 설치

# OpenSSL 윈도우 빌드
1. openssl-1.0.1c.tar.gz 압축 해제
2. cd openssl-1.0.1c
3. 콘솔창에서 VC++ 사용할 수 있도록 환경 설정
   "c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\vcvarsall.bat"
4. perl 로 설정파일 만들기(perl 설치파일 http://downloads.activestate.com/ActivePerl/releases/)
   win32 경우 ==> perl Configure VC-WIN32 --openssldir=C:\OpenSSL1.0.1
   win64 경우 ==> perl Configure VC-WIN64A --openssldir=C:\OpenSSL1.0.1
5. 컴파일 환경 설정 배치 실행
   win32 경우 ==> ms\do_ms.bat
   win64 경우 ==> ms\do_win64a.bat
6. 빌드
   .lib 빌드 ==> nmake -f ms\nt.mak install
   .dll 빌드 ==> nmake -f ms\ntdll.mak install
7. 결과 확인
   include 파일 ==> C:\OpenSSL1.0.1\include\openssl
   .lib(.dll) 파일 ==> C:\OpenSSL1.0.1\lib


#####


# OpenSSL 리눅스 빌드
1. openssl-1.0.1c.tar.gz 압축 해제
   tar zxvf openssl-1.0.1c.tar.gz
2. cd openssl-1.0.1c
3. 설정파일 만들기
   ./config --prefix=/home/ysoftman/openssl1.0.1
4. 빌드 후 테스트
   make && make test
5. 설치
   make install
6. 결과 확인
   include 파일 ==> /home/ysoftman/openssl1.0.1/include/openssl
   .a 파일 ==> /home/ysoftman/openssl1.0.1/lib


#####


# redhat, centos 에서 설치
sudo yum install -y pcre-devel
sudo yum install -y openssl-devel

# debian, ubuntu 에서 설치
sudo apt-get install -y libpcre3-dev
sudo apt-get install -y libssl-dev
sudo apt-get install -y libz-dev

#####


# mac(darwin) 에서 설치
brew install openssl
# openssl-devel 가 없기 때문에 openssl 의 include, lib 파일을 링크해준다.
echo 'y' | ln -s /usr/local/opt/openssl/include/openssl /usr/local/include
echo 'y' | ln -s /usr/local/opt/openssl/lib/libssl.1.0.0.dylib /usr/local/lib

# mac 기본 openssl(LibreSSL) 이 있다.
# /usr/bin/openssl # openssl(LibreSSL)
# openssl(OpenSSL) 을 설치하면 다음 경로에 생성된다.
# /usr/local/opt/openssl/bin/openssl  # openssl(OpenSSL)
brew install openssl

# /usr/local/opt/openssl/bin/openssl 이 우선 하는지 확인
which -a openssl
/usr/local/opt/openssl/bin/openssl
/usr/bin/openssl

# openssl(OpenSSL) 경로를 우선하지 않다면 우선하도록 PATH 환경변수 변경하자.
export PATH=/usr/local/opt/openssl/bin/openssl:$PATH



#####


# 다음 옵션들로 현재 참고하고 있는 include <...>, LIBRARY_PATH 설정을 파악할 수 있다.
# -x 언어
# -v verbose
# -E 지정된 장치(stage)에서 preprocessor 만 수행한다.
g++ -x c++ -v -E /dev/null