OpenSSL 로 ROOT CA 생성 및 SSL 인증서 발급

간단하게 CA 를 구성하려면 openssl 을 래핑한 easy rsa 를 사용하세요.


개요

웹서비스에 https 를 적용할 경우 SSL 인증서를 VeriSign 이나 Thawte, GeoTrust 등에서 인증서를 발급받아야 하지만 비용이 발생하므로 실제 운영 서버가 아니면 발급 받는데 부담이 될 수 있다.

이럴때 OpenSSL 을 이용하여 인증기관을 만들고 Self signed certificate 를 생성하고 SSL 인증서를 발급하는 법을 정리해 본다.

발급된 SSL 인증서는 apache httpd 등의 Web Server 에 설치하여 손쉽게 https 서비스를 제공할 수 있다.


Self Signed Certificate ?

인증서(digital certificate)는 개인키 소유자의 공개키(public key)에 인증기관의 개인키로 전자서명한 데이타다.

모든 인증서는 발급기관(CA) 이 있어야 하나 최상위에 있는 인증기관(root ca)은 서명해줄 상위 인증기관이 없으므로 root ca의 개인키로 스스로의 인증서에 서명하여 최상위 인증기관 인증서를 만든다.

이렇게 스스로 서명한 ROOT CA 인증서를 Self Signed Certificate(SSC) 라고 부른다.

IE, FireFox, Chrome 등의 Web Browser 제작사는 VeriSign 이나 comodo 같은 유명 ROOT CA 들의 인증서를 신뢰하는 CA로 브라우저에 미리 탑재해 놓는다.

저런 기관에서 발급된 SSL 인증서를 사용해야 browser 에서는 해당 SSL 인증서를 신뢰할수 있는데 OpenSSL 로 만든 ROOT CA와 SSL 인증서는 Browser가 모르는 기관이 발급한 인증서이므로 보안 경고를 발생시킬 것이나 테스트 사용에는 지장이 없다.

ROOT CA 인증서를 Browser에 추가하여 보안 경고를 발생시키지 않으려면 Browser 에 SSL 인증서 발급기관 추가하기 를 참고하자.


Certificate Signing Request?

공개키 기반(PKI)은 private key(개인키)와 public key(공개키)로 이루어져 있다.

인증서라고 하는 것은 내 공개키가 맞다고 인증기관(CA)이 전자서명하여 주는 것이며 나와 보안 통신을 하려는 당사자는 내 인증서를 구해서 그 안에 있는 공개키를 이용하여 보안 통신을 할 수 있다.

CSR(Certificate Signing Request) 은 인증기관에 인증서 발급 요청을 하는 특별한 ASN.1 형식의 파일이며(PKCS#10 - RFC2986)  그 안에는 내 공개키 정보와 사용하는 알고리즘 정보등이 들어 있다.

개인키는 외부에 유출되면 안 되므로 저런 특별한 형식의 파일을 만들어서 인증기관에 전달하여 인증서를 발급 받는다.

SSL 인증서 발급시 CSR 생성은 Web Server 에서 이루어지는데 Web Server 마다 방식이 상이하여 사용자들이 CSR 생성등을 어려워하니 인증서 발급 대행 기관에서 개인키까지 생성해서 보내주고는 한다.

ROOT CA 인증서 생성

openssl 로 root ca 의 개인키와 인증서를 만들어 보자

  1. CA 가 사용할 RSA  key pair(public, private key) 생성

    2048bit 개인키 생성
    openssl genrsa -aes256 -out lesstif-rootca.key 2048

    개인키 분실에 대비해 AES 256bit 로 암호화한다. AES 이므로 암호(pass phrase)를 분실하면 개인키를 얻을수 없으니 꼭 기억해야 한다.

  2. 개인키 권한 설정

    보안 경고

    개인키의 유출 방지를 위해 소유자만 읽을수 있도록 group 과 other의 permission 을 모두 제거하는게 좋다.

    chmod 600 lesstif-rootca.key
  3. CSR(Certificate Signing Request) 생성을 위한 openssl 설정 파일을 만들고 rootca_openssl.conf(변경 가능) 로 저장한다.

    rootca_openssl.conf
    [ req ]
    default_bits            = 2048
    default_md              = sha1
    default_keyfile         = lesstif-rootca.key
    distinguished_name      = req_distinguished_name
    extensions             = v3_ca
    req_extensions = v3_ca
     
    [ v3_ca ]
    basicConstraints       = critical, CA:TRUE, pathlen:0
    subjectKeyIdentifier   = hash
    ##authorityKeyIdentifier = keyid:always, issuer:always
    keyUsage               = keyCertSign, cRLSign
    nsCertType             = sslCA, emailCA, objCA
    [req_distinguished_name ]
    countryName                     = Country Name (2 letter code)
    countryName_default             = KR
    countryName_min                 = 2
    countryName_max                 = 2
    
    # 회사명 입력
    organizationName              = Organization Name (eg, company)
    organizationName_default      = lesstif Inc.
     
    # 부서 입력
    #organizationalUnitName          = Organizational Unit Name (eg, section)
    #organizationalUnitName_default  = Condor Project
     
    # SSL 서비스할 domain 명 입력
    commonName                      = Common Name (eg, your name or your server's hostname)
    commonName_default             = lesstif's Self Signed CA
    commonName_max                  = 64 

    Root CA 용 CSR 요청 파일을 생성한다.

    인증서 요청 생성
    openssl req -new -key lesstif-rootca.key -out lesstif-rootca.csr -config rootca_openssl.conf

    아래는 OpenSSL 의 프롬프트

    인증서 요청 생성
    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) [KR]:
    Organization Name (eg, company) [lesstif Inc]:lesstif Inc.
    Common Name (eg, your name or your servers hostname) [lesstif's Self Signed CA]:lesstif's Self Signed CA
  4. 10년짜리 self-signed 인증서를 생성한다. 인증서는 -out 옵션 뒤에 기술한 파일명(예: lesstif-rootca.crt) 으로 생성된다.

    -extensions v3_ca 옵션을 추가해야 한다.
    openssl x509 -req -days 3650 \
    -extensions v3_ca \
    -set_serial 1 \
    -in lesstif-rootca.csr \
    -signkey lesstif-rootca.key \
    -out lesstif-rootca.crt \
    -extfile rootca_openssl.conf

    서명에 사용할 해시 알고리즘을 변경하려면 -sha256, -sha384, -sha512 처럼 해시를 지정하는 옵션을 전달해 준다.

    기본값은 -sha256 이며 openssl 1.0.2 이상이 필요

  5. 제대로 생성되었는지 확인을 위해 인증서의 정보를 출력해 본다.

    openssl x509 -text -in lesstif-rootca.crt
     Click here to expand...
    Certificate:
        Data:
            Version: 3 (0x2)
            Serial Number: 1 (0x1)
            Signature Algorithm: sha256WithRSAEncryption
            Issuer: C = KR, O = lesstif Inc., CN = lesstifs Self Signed CA
            Validity
                Not Before: Oct  8 00:47:36 2021 GMT
                Not After : Oct  6 00:47:36 2031 GMT
            Subject: C = KR, O = lesstif Inc., CN = lesstifs Self Signed CA
            Subject Public Key Info:
                Public Key Algorithm: rsaEncryption
                    RSA Public-Key: (2048 bit)
                    Modulus:
                        00:d1:89:a7:8a:c3:d8:ef:1b:70:b5:3e:a1:1f:89:
                        14:00:d8:ce:67:ad:a6:23:67:f3:be:18:03:21:f3:
                        04:a4:d2:a1:92:9b:f3:71:e7:e3:b4:52:f1:6f:c8:
                        8c:be:28:6f:13:ad:04:36:b0:32:ab:37:f0:68:81:
                        b0:33:eb:68:ef:10:1e:ab:17:4a:3b:92:6e:e6:2f:
                        68:32:0f:d9:24:d6:26:24:42:c9:12:60:d8:3d:60:
                        36:93:cb:73:68:d8:11:94:1c:ee:26:22:24:25:70:
                        65:f4:13:81:52:8d:1f:2c:6f:a8:e5:77:f3:05:fd:
                        dd:50:d3:b0:93:6a:d7:23:3f:35:73:c2:ef:e2:42:
                        ce:a4:46:c2:1f:2f:2c:ac:56:51:18:62:49:17:13:
                        3a:cc:59:ff:8c:e7:8c:fe:21:d2:1e:d5:ad:75:b1:
                        3e:b1:be:52:bf:4e:53:46:48:c8:15:6a:56:c0:77:
                        1b:13:de:20:14:ad:01:0a:c8:0d:96:cd:ac:9b:10:
                        1f:cb:8d:0f:59:20:5c:44:ab:b2:46:b9:60:ba:e4:
                        7d:11:a3:a5:f9:8a:d6:26:4a:f1:a0:e9:e6:c8:4c:
                        8b:29:83:89:ae:a7:ad:ac:21:76:96:aa:6e:58:99:
                        89:d0:8a:f3:1b:b5:04:e4:c1:11:bb:ff:2a:82:a5:
                        0d:f3
                    Exponent: 65537 (0x10001)
            X509v3 extensions:
                X509v3 Basic Constraints: critical
                    CA:TRUE, pathlen:0
                X509v3 Subject Key Identifier:
                    1B:15:F8:0E:D9:A2:E2:7A:0D:3D:DB:B4:CF:7B:35:F2:CB:B3:FC:BE
                X509v3 Key Usage:
                    Certificate Sign, CRL Sign
                Netscape Cert Type:
                    SSL CA, S/MIME CA, Object Signing CA
        Signature Algorithm: sha256WithRSAEncryption
             12:4f:52:d8:cf:e2:51:4f:93:a7:5e:ae:06:3b:7c:e3:82:48:
             eb:1c:c5:4c:cd:c6:62:4e:c7:90:7a:18:f8:00:2e:78:f2:e0:
             d5:c8:3a:6d:8e:e1:b3:81:81:a4:6e:0c:cc:b9:45:27:b1:76:
             e0:d5:d6:18:6f:a0:5f:a3:8f:66:8c:2f:42:43:f7:85:ce:7d:
             87:4e:47:76:4a:a2:20:3a:1b:b6:6a:69:0a:f8:a6:2c:c4:f6:
             42:2e:cf:7d:c4:08:aa:50:91:32:c8:00:0d:02:31:33:90:70:
             9a:d6:97:2b:1f:70:18:c3:46:cd:13:3b:5d:ce:22:56:82:b2:
             d9:ba:b6:ac:c5:3b:96:70:88:75:2a:a9:f6:de:42:e1:64:95:
             1a:ab:07:49:f5:10:b4:1e:79:9c:75:c2:9f:41:6d:fe:ee:2d:
             13:bc:c6:7f:3e:35:12:ae:f7:b9:fa:24:78:ed:12:8b:9c:e0:
             8a:20:b0:ad:fb:ab:4a:06:3b:96:eb:38:bf:89:7a:7e:c8:a7:
             99:7d:3b:57:c5:ed:41:48:f6:c7:5e:e1:cb:7f:c7:86:78:e6:
             20:70:91:78:ed:f8:8b:54:8d:38:00:d7:1c:e7:e4:3f:86:27:
             7f:b2:e5:ae:3d:b5:fa:43:3b:3a:68:41:02:f5:34:3d:68:21:
             83:fc:0a:ec
    -----BEGIN CERTIFICATE-----
    MIIDXDCCAkSgAwIBAgIBATANBgkqhkiG9w0BAQsFADBGMQswCQYDVQQGEwJLUjEV
    MBMGA1UECgwMbGVzc3RpZiBJbmMuMSAwHgYDVQQDDBdsZXNzdGlmcyBTZWxmIFNp
    Z25lZCBDQTAeFw0yMTEwMDgwMDQ3MzZaFw0zMTEwMDYwMDQ3MzZaMEYxCzAJBgNV
    BAYTAktSMRUwEwYDVQQKDAxsZXNzdGlmIEluYy4xIDAeBgNVBAMMF2xlc3N0aWZz
    IFNlbGYgU2lnbmVkIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
    0YmnisPY7xtwtT6hH4kUANjOZ62mI2fzvhgDIfMEpNKhkpvzcefjtFLxb8iMvihv
    E60ENrAyqzfwaIGwM+to7xAeqxdKO5Ju5i9oMg/ZJNYmJELJEmDYPWA2k8tzaNgR
    lBzuJiIkJXBl9BOBUo0fLG+o5XfzBf3dUNOwk2rXIz81c8Lv4kLOpEbCHy8srFZR
    GGJJFxM6zFn/jOeM/iHSHtWtdbE+sb5Sv05TRkjIFWpWwHcbE94gFK0BCsgNls2s
    mxAfy40PWSBcRKuyRrlguuR9EaOl+YrWJkrxoOnmyEyLKYOJrqetrCF2lqpuWJmJ
    0IrzG7UE5MERu/8qgqUN8wIDAQABo1UwUzASBgNVHRMBAf8ECDAGAQH/AgEAMB0G
    A1UdDgQWBBQbFfgO2aLieg0927TPezXyy7P8vjALBgNVHQ8EBAMCAQYwEQYJYIZI
    AYb4QgEBBAQDAgAHMA0GCSqGSIb3DQEBCwUAA4IBAQAST1LYz+JRT5OnXq4GO3zj
    gkjrHMVMzcZiTseQehj4AC548uDVyDptjuGzgYGkbgzMuUUnsXbg1dYYb6Bfo49m
    jC9CQ/eFzn2HTkd2SqIgOhu2amkK+KYsxPZCLs99xAiqUJEyyAANAjEzkHCa1pcr
    H3AYw0bNEztdziJWgrLZurasxTuWcIh1Kqn23kLhZJUaqwdJ9RC0HnmcdcKfQW3+
    7i0TvMZ/PjUSrve5+iR47RKLnOCKILCt+6tKBjuW6zi/iXp+yKeZfTtXxe1BSPbH
    XuHLf8eGeOYgcJF47fiLVI04ANcc5+Q/hid/suWuPbX6Qzs6aEEC9TQ9aCGD/Ars
    -----END CERTIFICATE-----


SSL 인증서 발급

위에서 생성한 root ca 서명키로 SSL 인증서를 발급해 보자

키 쌍 생성

1. SSL 호스트에서 사용할 RSA  key pair(public, private key) 생성

2048bit 개인키 생성
openssl genrsa -aes256 -out lesstif.com.key 2048


2. Remove Passphrase from key

개인키를 보호하기 위해 Key-Derived Function 으로 개인키 자체가 암호화되어 있다. 인터넷 뱅킹등에 사용되는 개인용 인증서는 당연히 저렇게 보호되어야 하지만 SSL 에 사용하려는 키가 암호가 걸려있으면 웹 서버 구동때마다 pass phrase 를 입력해야 하므로 암호를 제거한다.

개인키 pass phrase 제거
cp  lesstif.com.key  lesstif.com.key.enc
openssl rsa -in  lesstif.com.key.enc -out lesstif.com.key

보안 경고

개인키의 유출 방지를 위해 group 과 other의 permission 을 모두 제거한다.

chmod 600 lesstif.com.key*

CSR 생성

1. CSR(Certificate Signing Request) 생성을 위한 openssl config 파일을 만들고 host_openssl.conf(변경 가능) 라는 이름으로 저장한다.

host_openssl.conf
[ req ]
default_bits            = 2048
default_md              = sha1
default_keyfile         = lesstif-rootca.key
distinguished_name      = req_distinguished_name
extensions             = v3_user
## 인증서 요청시에도 extension 이 들어가면 authorityKeyIdentifier 를 찾지 못해 에러가 나므로 막아둔다.
## req_extensions = v3_user

[ v3_user ]
# Extensions to add to a certificate request
basicConstraints = CA:FALSE
authorityKeyIdentifier = keyid,issuer
subjectKeyIdentifier = hash
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
## SSL 용 확장키 필드
extendedKeyUsage = serverAuth,clientAuth
subjectAltName          = @alt_names
[ alt_names]
## Subject AltName의 DNSName field에 SSL Host 의 도메인 이름을 적어준다.
## 멀티 도메인일 경우 *.lesstif.com 처럼 쓸 수 있다.
DNS.1   = www.lesstif.com
DNS.2   = lesstif.com
DNS.3   = *.lesstif.com

[req_distinguished_name ]
countryName                     = Country Name (2 letter code)
countryName_default             = KR
countryName_min                 = 2
countryName_max                 = 2

# 회사명 입력
organizationName              = Organization Name (eg, company)
organizationName_default      = lesstif Inc.
 
# 부서 입력
organizationalUnitName          = Organizational Unit Name (eg, section)
organizationalUnitName_default  = lesstif SSL Project
 
# SSL 서비스할 domain 명 입력
commonName                      = Common Name (eg, your name or your server's hostname)
commonName_default             = lesstif.com
commonName_max                  = 64


인증서 발급 요청(CSR) 파일을 생성한다.

openssl req -new -key lesstif.com.key -out lesstif.com.csr -config host_openssl.conf



SSL 인증서 요청
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) [KR]:
Organization Name (eg, company) [lesstif Inc]:lesstif's Self Signed CA
Common Name (eg, your name or your servers hostname) [lesstif.com]:*.lesstif.com


5년짜리 lesstif.com 용 SSL 인증서 발급 (서명시 ROOT CA 개인키로 서명)

openssl x509 -req -days 1825 -extensions v3_user -in lesstif.com.csr \
-CA lesstif-rootca.crt -CAcreateserial \
-CAkey  lesstif-rootca.key \
-out lesstif.com.crt  -extfile host_openssl.conf


제대로 생성되었는지 확인을 위해 인증서의 정보를 출력해 본다.

openssl x509 -text -in lesstif.com.crt


검증이 끝났으면 web server 에서 읽을수 있도록 시스템의 표준 개인키와 인증서 디렉터리에 복사해 준다.

cp lesstif.com.crt  /etc/pki/tls/certs/
cp lesstif.com.key /etc/pki/tls/private/