ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • openssl 로 self-signed certificate 만들기
    linux 2021. 9. 10. 11:56
    반응형

    서버에서 사용할 self-signed 인증서를 만드려고 한다.

    • X.509 extensions

    보통 브라우저에서는 상관없지만, Docker api 등에서는 인증서의 v3 extension 필드를 요구하는 경우가 있다. 이 경우를 위해 extension 의 일부 필드를 사용한다.

    - basicConstraints: root 인증서에서 사용할 필드이다. 다른 인증서(서버용 인증서) 에 서명을 하는 경우 필요하다.

    - subjectAltName: 서버 인증서에서 사용할 필드이다. 도메인과 일치하는 DNS 값이 있어야 한다. 이전에는 CN(Common Name) 만 도메인과 동일하면 문제가 되지 않았는데, 도커 20.10.8 에서는 api 사용 시 이 값이 도메인과 일치하는 것을 요구해서 추가하였다.

     

    openssl 에서 extension 파라미터를 넘기는 방법이 여러개 있는데, 여기서는 파일을 전달하는 방식을 사용한다.

    또한, 파일 전달 형식에서도,-extfile {{config 파일명}} -extensions {{section이름}} 으로 진행하는 방법이 있고, section 이름 없이 필요한 정보만 적은 파일을 -extfile 로 전달하는 방식이 있는데 후자를 선택한다. (-extensions 가 없으면 default section (파일 내에서 별도로 section 으로 정의하지 않은 영역) 을 사용하게 된다.)

     

    extensions 의 종류와 파라미터 전달 방식은 아래를 참고:

    - x509 명령어 옵션들: https://www.openssl.org/docs/manmaster/man1/openssl-x509.html

    - v3 conig 에 들어갈 수 있는 값, 포맷 정리: https://www.openssl.org/docs/manmaster/man5/x509v3_config.html

    • 진행 환경:

    동일한 환경을 유지 하기 위해서 docker 컨테이너를 이용하였지만, 굳이 docker 컨테이너 내부에서 진행할 필요는 없다. 혹시 docker 컨테이너를 사용하려고 한다면 결과물을 호스트 서버로 꺼내야 하니까 마운트 하는 것을 잊지 말자.

    - Rocky Linux 8.5 (docker image)
    - root 로 진행
    - openssl 버전: 1.1.1k (yum install 로 설치한 경우)

    • 인증서 내용:


    1. openssl 설치

    yum 으로 설치한다.

    # yum -y install openssl

    버전 확인

    # openssl version
    OpenSSL 1.1.1k  FIPS 25 Mar 2021

    2. root 인증서

    2-1. root 를 위한 키를 우선 만든다.

    # openssl genrsa -aes256 -out root.key 2048
    Generating RSA private key, 2048 bit long modulus (2 primes)
    ........+++++
    ..................................+++++
    e is 65537 (0x010001)
    Enter pass phrase for root.key:
    Verifying - Enter pass phrase for root.key:

    이 때, pass phrase 를 요구한다. 나중에 서버 인증서 서명시 필요하니 기억해야 한다.

    참고로 비밀번호가 4개 보다 작으면 아래처럼 에러가 발생한다.

    UI routines:UI_set_result_ex:result too small:crypto/ui/ui_lib.c:905:You must type in 4 to 1023 characters

    또한, 일반적으로는 문제가 없지만, 혹시 권한 문제가 있다면 아래처럼 권한을 변경한다.

    # chmod 600 root.key

    그 다음은 CSR(Certificate Signing Request) 을 만들자. 미리 정한 값을 넣는다.

    # openssl req -new -key root.key -out root.csr
    Enter pass phrase for root.key:
    You are about to be asked to enter information that will be incorporated
    into your certificate request.
    What you are about to enter is what is called a Distinguished Name or a DN.
    There are quite a few fields but you can leave some blank
    For some fields there will be a default value,
    If you enter '.', the field will be left blank.
    -----
    Country Name (2 letter code) [XX]:KR
    State or Province Name (full name) []:
    Locality Name (eg, city) [Default City]:Seoul
    Organization Name (eg, company) [Default Company Ltd]:bitgadak
    Organizational Unit Name (eg, section) []:
    Common Name (eg, your name or your server's hostname) []:bitgadak root
    Email Address []:
    
    Please enter the following 'extra' attributes
    to be sent with your certificate request
    A challenge password []:
    An optional company name []:

    잘 들어갔는지 확인해 보자

    # openssl req -in root.csr -noout -text
    Certificate Request:
        Data:
            Version: 1 (0x0)
            Subject: C = KR, L = Seoul, O = bitgadak, CN = bitgadak root
            Subject Public Key Info:
                Public Key Algorithm: rsaEncryption
                    RSA Public-Key: (2048 bit)
                    Modulus:
                        (...생략...)
                    Exponent: 65537 (0x10001)
            Attributes:
                a0:00
        Signature Algorithm: sha256WithRSAEncryption
             (...생략...)

    이제 인증서를 만들어야 하는데, 거기에 전달할 extensions 을 위한 파일을 만들자. 파일명은 root.ext 로 하였다.

    root 에서 필요한 확장 필드는 basicConstraints 이다.

    # cat root.ext
    basicConstraints = CA:TRUE

    이제 위에서 만든 CSR 과 extension 파일을 가지고 인증서를 만든다. (10년)

    # openssl x509 -req -days 3650 -in root.csr -signkey root.key -extfile root.ext -out root.crt
    Signature ok
    subject=C = KR, L = Seoul, O = bitgadak, CN = bitgadak root
    Getting Private key
    Enter pass phrase for root.key:

    내용을 확인해 보자

    # openssl x509 -text -in root.crt
    Certificate:
        Data:
            Version: 3 (0x2)
            Serial Number:
                (...생략...)
            Signature Algorithm: sha256WithRSAEncryption
            Issuer: C = KR, L = Seoul, O = bitgadak, CN = bitgadak root
            Validity
                Not Before: Sep 10 01:48:21 2021 GMT
                Not After : Sep  8 01:48:21 2031 GMT
            Subject: C = KR, L = Seoul, O = bitgadak, CN = bitgadak root
            Subject Public Key Info:
                Public Key Algorithm: rsaEncryption
                    RSA Public-Key: (2048 bit)
                    Modulus:
                        (...생략...)
                    Exponent: 65537 (0x10001)
            X509v3 extensions:
                X509v3 Basic Constraints: 
                    CA:TRUE
        Signature Algorithm: sha256WithRSAEncryption
             (...생략...)
    -----BEGIN CERTIFICATE-----
    (...생략...)
    -----END CERTIFICATE-----

    extensiosn 도 잘 들어가 있다.

    3. 서버용 인증서

    key 를 만들자. 일단은 비밀번호를 추가해서 만들어야 한다.

    # openssl genrsa -aes256 -out server-with-password.key 2048
    Generating RSA private key, 2048 bit long modulus (2 primes)
    ..............+++++
    ....................................+++++
    e is 65537 (0x010001)
    Enter pass phrase for server-with-password.key:
    Verifying - Enter pass phrase for server-with-password.key:

    비밀번호를 제거한 버전을 만든다.

    # openssl rsa -in server-with-password.key -out server.key
    Enter pass phrase for server-with-password.key:
    writing RSA key

    서버용 CSR 생성

    # openssl req -new -key server.key -out server.csr
    You are about to be asked to enter information that will be incorporated
    into your certificate request.
    What you are about to enter is what is called a Distinguished Name or a DN.
    There are quite a few fields but you can leave some blank
    For some fields there will be a default value,
    If you enter '.', the field will be left blank.
    -----
    Country Name (2 letter code) [XX]:KR
    State or Province Name (full name) []: 
    Locality Name (eg, city) [Default City]:Seoul
    Organization Name (eg, company) [Default Company Ltd]:bitgadak
    Organizational Unit Name (eg, section) []:
    Common Name (eg, your name or your server's hostname) []:bitgadak.tistory.com
    Email Address []:
    
    Please enter the following 'extra' attributes
    to be sent with your certificate request
    A challenge password []:
    An optional company name []:

    인증서 생성시 필요한 extensions 를 적은 파일을 만든다. 이름은 server.ext 로 하였다.

    여기서 필요한 확장 필드는 subjectAltName 이다. 여러 개가 필요한 경우 DNS.1, DNS.2 처럼 넣을 수 있는데, 일단 하나만 적었다. @alt_names 는 alt_names 섹션 ([alt_names] 이하 영역) 을 불러온다는 의미이다.

    # cat server.ext
    subjectAltName = @alt_names
    
    [alt_names]
    DNS = bitgadak.tistory.com

    이제 인증서를 만들자 (1년)

    # openssl x509 -req -days 365 -in server.csr -extfile server.ext \
      -CA root.crt -CAkey root.key -CAcreateserial -out server.crt
    Signature ok
    subject=C = KR, L = Seoul, O = bitgadak, CN = bitgadak.tistory.com
    Getting CA Private Key
    Enter pass phrase for root.key:

    확인해 보자

    # openssl x509 -text -in server.crt
    Certificate:
        Data:
            Version: 3 (0x2)
            Serial Number:
                (...생략...)
            Signature Algorithm: sha256WithRSAEncryption
            Issuer: C = KR, L = Seoul, O = bitgadak, CN = bitgadak root
            Validity
                Not Before: Sep 10 01:58:59 2021 GMT
                Not After : Sep 10 01:58:59 2022 GMT
            Subject: C = KR, L = Seoul, O = bitgadak, CN = bitgadak.tistory.com
            Subject Public Key Info:
                Public Key Algorithm: rsaEncryption
                    RSA Public-Key: (2048 bit)
                    Modulus:
                        (...생략...)
                    Exponent: 65537 (0x10001)
            X509v3 extensions:
                X509v3 Subject Alternative Name: 
                    DNS:bitgadak.tistory.com
        Signature Algorithm: sha256WithRSAEncryption
             (...생략...)
    -----BEGIN CERTIFICATE-----
    (...생략...)
    -----END CERTIFICATE-----

    완료되었다. 이제 서버에 적용하면 된다.

    4. 기타

    4-1. nginx 에서 사용시

    nginx 에서 사용하려면 root 인증서 정보가 포함된 crt 를 입력해야 한다고 한다. 순서가 중요하다.

     

    nginx 에서 사용할 crt 만들기. nginx 입장에서는 이름이 중요하진 않은데, server-chained.crt 라고 정했다.

    # cat server.crt root.crt > server-chained.crt

    이렇게 만든 파일을 nginx 의 설정 파일에서 server 영역 안에 넣어준다.

    예시:

    server {
        listen       443 ssl;
        (...생략...)
    
        ssl_certificate     /etc/nginx/server-chained.crt;
        ssl_certificate_key /etc/nginx/server.key;
    
        (...생략...)
    }

    4-2. CentOS 에서 신뢰할 수 있는 인정서 추가

    Self-Signed 의 경우 Docker api 사용시 에러가 나온다. CentOS 라면 root 인증서를 신뢰할 수 있는 인증서로 추가하면 해결된다.

     

    사용자가 인증서를 추가하는 경우엔

    /etc/pki/ca-trust/source/anchors/

    에 추가하고 

    $ sudo update-ca-trust

    이렇게 갱신하면 된다.

     

    Docker 가 인식하려면 Docker 의 재시작이 필요하다. 재시작 없이 리로딩 했으면 좋겠는데, 아직 방법을 모르겠다.

    수정사항

    • 2022-02-13: 인증서를 만든 컨테이너 이미지를 CentOS 8 에서 Rocky Linux 로 변경 (CentOS 8 저장소 만료로 인해 yum install 이 동작하지 않음)
    반응형

    댓글

Designed by Tistory.