Chistory
OpenSSL root CA 인증기관을 만들어보자. 본문
간혹 웹서비스나 TLS 통신 등을 구축할 때, 인증서가 필요하다.
오늘날의 인증 체계는, x509 기반의 인증서를 사용한다. 흔히 보는 ---BEGIN.....--- 이런식으로 시작하고, 암호화된 문자열이 있는 그 파일을 의미한다.
이런 인증서들은, 일종의 체인을 이뤄서 root CA로부터 인증을 받고, 그것들에 대한 key와 인증서를 가지고 웹 서버를 구동시키는 식으로 활용된다. 신뢰할 수 있는 root CA 로부터 인증을 받은 인증서들은, 웹 브라우저에서 안전한 페이지로 표시되곤 한다. 이러한 신뢰할 수 있는 인증 기관으로부터의 인증은, 도메인 기반으로 이루어지므로 일단 개인 소유의 도메인이 필요하며, Lets Encrypt 의 3개월 단위의 무료 인증이 아닌 경우, 비싼 요금을 내고 인증서를 발급받아야 한다.
물론 단순히 패킷에 대한 암호화가 필요한 경우, root CA를 직접 구축하여, 생성하고 폐기할 수 있다. 오늘은 이러한 root CA를 만드는 작업을 공유하려 한다. 다양한 방식이 있지만, 쉘 스크립트를 이용하여 간단하게 구축을 진행할 것이다.
먼저 간단한 리눅스 환경이 필요하다. 사전 설치가 필요한 것은, openssl 패키지 정도이다.
# CentOS
sudo yum install openssl
# Ubuntu
sudo apt-get install openssl
그리고 간단한 폴더, 파일 구조가 필요하다.
cd
mkdir rootca
cd rootca
mkdir newcert
mkdir oldcert
mkdir private
mkdir rootca
mkdir crl
touch index.txt
touch serial
touch crlnumber
인증서 생성에 관련된 주요 파일들을 보면, 먼저 인증 요청서가 있고, key가 있다. 여기에 이 두가지를 이용해 생성되는 인증서 파일, 그리고 Root CA에서 관리하는 인증서 폐기 목록이 있다. 인증 요청서는 보통 csr 파일이라고 부른다.
먼저 root CA 인증서에 사용될 csr을 생성해야 한다. 다음 명령어로 key 파일을 만든다.
openssl genrsa -aes256 -out rootca/rootca.key 2048
pass phrase 를 입력하라는 프롬프트가 나오면, 원하는 비밀번호를 입력한다.
다음으로 인증기관을 어떻게 설정할 지에 대한 설정 파일이 필요하다.
vim rootca_openssl.conf
#아래는 파일 내용
[ ca ]
default_ca = CA_default # The default ca section
[ CA_default ]
dir = . # Where everything is kept
certs = $dir/certs # Where the issued certs are kept
crl_dir = $dir/crl # Where the issued crl are kept
database = $dir/index.txt # database index file.
#unique_subject = no # Set to 'no' to allow creation of
# several ctificates with same subject.
new_certs_dir = $dir/newcerts # default place for new certs.
certificate = $dir/rootca.crt # The CA certificate
serial = $dir/serial # The current serial number
crlnumber = $dir/crlnumber # the current crl number
# must be commented out to leave a V1 CRL
crl = $dir/crl.pem # The current CRL
private_key = $dir/private/cakey.pem# The private key
RANDFILE = $dir/private/.rand # private random number file
x509_extensions = usr_cert # The extentions to add to the cert
# Comment out the following two lines for the "traditional"
# (and highly broken) format.
name_opt = ca_default # Subject Name options
cert_opt = ca_default # Certificate field options
default_days = 365 # how long to certify for
default_crl_days= 30 # how long before next CRL
default_md = sha1 # which md to use.
preserve = no # keep passed DN ordering
policy = policy_match
[ policy_match ]
countryName = match
stateOrProvinceName = match
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ policy_anything ]
countryName = optional
stateOrProvinceName = optional
localityName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ req ]
default_bits = 2048
default_keyfile = privkey.pem
distinguished_name = req_distinguished_name
attributes = req_attributes
x509_extensions = v3_ca # The extentions to add to the self signed cert
string_mask = default
[ req_distinguished_name ]
countryName = Country Name (2 letter code)
countryName_default = KR
countryName_min = 2
countryName_max = 2
stateOrProvinceName = State or Province Name (full name)
stateOrProvinceName_default = YourOrganizationName
localityName = Locality Name (eg, city)
0.organizationName = Organization Name (eg, company)
0.organizationName_default = YourOrganizationName
# we can do this but it is not needed normally
#1.organizationName = Second Organization Name (eg, company)
#1.organizationName_default = World Wide Web Pty Ltd
organizationalUnitName = Organizational Unit Name (eg, section)
#organizationalUnitName_default =
commonName = Common Name (eg, YOUR name) #이름 등을 적는다.
commonName_max = 64
emailAddress = Email Address #메일 주소를 적는다.
emailAddress_max = 64
[ req_attributes ]
challengePassword = A challenge password
challengePassword_min = 4
challengePassword_max = 20
unstructuredName = An optional company name
[ usr_cert ]
nsComment = "OpenSSL Generated Certificate"
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer
crlDistributionPoints=@cdp_section
nsCaRevocationUrl = http://192.168.1.3/cert/carevoke
nsRevocationUrl = http://192.168.1.3/cert/revoke
[ v3_req ]
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
[ v3_ca ]
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid:always,issuer:always
[ crl_ext ]
authorityKeyIdentifier=keyid:always,issuer:always
[ proxy_cert_ext ]
basicConstraints=CA:FALSE
nsComment = "OpenSSL Generated Certificate"
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer:always
[crldp1_section]
[cdp_section]
URI=http://192.168.1.3/cert/crl.pem
http로 시작하는 주소는, CDP, 즉 인증서 폐기 목록 배포 포인트를 지정해주는 것이다. 웹 서버를 직접 구축하면 가능하긴 한데, 여기선 굳이 신경쓰지 않아도 된다. 만약 apache나 nginx로 웹 서버를 구성중이라면, 해당 경로를 web root로 놓으면 배포 포인트로 활용할 수 있다. 보통 웹도 쓰이지만, ldap등의 다른 체계를 사용하기도 한다.
req_distinguished_name 섹션 내부의 내용은, 필요에 따라 적절히 바꿔서 입력한다. 입력하지 않아도, 다음 단계에서 입력하라는 프롬프트가 나타나긴 한다.
openssl req -new -key rootca/rootca.key -out rootca/rootca.csr -config rootca_openssl.conf
위 커맨드를 입력하면, root ca에 대한 CSR 파일을 생성한다. 프롬프트 안내에 따라, 인증서 생성에 필요한 요청서를 만들어준다.
아래 커맨드로 10년짜리 루트 인증서를 발급하면, 일단 인증 기관이 완성된다.
openssl x509 -req -days 3650 -extensions v3_ca -set_serial 1 -in rootca/rootca.csr -signkey rootca/rootca.key -out rootca/rootca.crt -extfile rootca_openssl.conf
다음 커맨드로 제대로 완성이 되었나 확인해보자
openssl x509 -text -in rootca/rootca.crt
이제 이 rootca로 새로운 인증서를 찍어낼 차례다. 이 인증기관에 요청할 요청서와, private key가 필요하다.
아래 커맨드로 새로운 csr 요청서를 생성할 수 있다.
openssl genrsa -aes256 -out private/tmp.key 2048
openssl rsa -in private/tmp.key -out private/new.key
openssl req -new -key private/new.key -sha256 -out private/new.csr
csr을 만들었으면, 새로운 인증서에도 적용할 conf 파일을 작성한다.
vim host.conf
#아래는 작성할 내용
[ v3_user ]
# Extensions to add to a certificate request
basicConstraints = CA:TRUE
authorityKeyIdentifier = keyid,issuer
subjectKeyIdentifier = hash
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
## SSL 용 확장키 필드
extendedKeyUsage = serverAuth,clientAuth
[ usr_cert ]
crlDistributionPoints=@cdp_section
nsCaRevocationUrl = http://192.168.1.3/cert/carevoke
nsRevocationUrl = http://192.168.1.3/cert/revoke
[cdp_section]
URI=http://192.168.1.3/cert/crl.pem
흔히 사용되는 옵션들이다. 마지막으로 아래 커맨드로 새로운 인증서를 생성한다.
openssl x509 -req -days 1825 -extensions v3_user -extensions usr_cert -in private/new.csr -CA rootca/rootca.crt -CAcreateserial -CAkey rootca/rootca.key -out newcert/new.crt -extfile host.conf
이제 newcert 디렉토리에 new.crt 라는 인증서가 생성된 것을 확인할 수 있다.
이를 간단하게 CSR로부터 인증서를 생성하고, 특정 인증서를 폐기하는 시스템을 쉘 스크립트로 작성할 수 있다.
간단한 쉘 스크립트로, csr파일에 대한 처리를 해주는 스크립트를 만든다.
vim cert.sh
#!/bin/bash
CUR=`pwd`
CONF="rootca_openssl.conf"
HOST_CONF="host.conf"
cd $CUR
usage(){
echo "$0 revoke [newcert/certname]"
echo "$0 new [csrfile] [title]"
exit
}
if [ $# -lt 2 ] || [ $# -gt 3 ]; then
usage
fi
if [ "$1" = "new" ]; then
if [ $# -ne 3 ] ; then
usage
fi
openssl x509 -req -days 1825 -extensions v3_user -extensions usr_cert -in $2 -CA rootca/rootca.crt -CAcreateserial -CAkey rootca/rootca.key -out newcert/$3.crt -extfile $HOST_CONF
elif [ "$1" = "revoke" ]; then
openssl ca -keyfile rootca/rootca.key -cert rootca/rootca.crt -revoke $2 -config $CONF
openssl ca -keyfile rootca/rootca.key -cert rootca/rootca.crt -gencrl -out rootca/rootca.crl -config $CONF
mv $2 ${CUR}/oldcert
else
usage
fi
#최초 설정 부분
#스크립트 권한 부여
chmod 755 cert.sh
echo -n "00" > crlnumber
#사용법
#인증서 생성
./cert.sh new [새로운 인증요청서] [인증서파일이름]
#인증서 폐기
./cert.sh revoke [폐기할 인증서]
인증서를 폐기할 경우, index.txt에 폐기 목록이 업데이트된다.
인증서를 생성하면, newcert 디렉토리에 생성한 파일 이름으로 인증서가 들어간다.
이렇게 구축한 인증서는, 다양한 서비스에서 패킷 암호화에 사용할 수 있다.
'개발 & CS > Linux' 카테고리의 다른 글
라이브 디스크 파티션 사이즈 변경 (0) | 2020.08.24 |
---|---|
프록시 솔루션간단 비교.. (0) | 2020.01.03 |
haproxy libssl 에러 (0) | 2020.01.03 |
리눅스 명령어 3. 파일명 일괄변경? (1) | 2019.12.16 |
리눅스 명령어 2. test와 if (0) | 2019.12.05 |