๐ค ์ฃผ์
ํด๋น ํฌ์คํ ์ ๋จ์ํ Spring Boot์ HTTPS๋ฅผ ์ ์ฉํ๋ ๊ฒ์ ๋ชฉ์ ์ผ๋ก ํ๋ ํฌ์คํ ์ด ์๋ cert manager๋ฅผ ์ดํดํ๊ณ kubernetes์์ https ์ ์ฉ์ ์๋ํํ๋ ๊ฒ์ ๋ชฉ์ ์ผ๋ก ํฉ๋๋ค. ์์ง cert manager์ ๋ํด ์ ๋๋ก ์ดํดํ๊ณ ์์ง ์๋ค๋ฉด ์ด์ ๊ธ์ ์ฐธ๊ณ ํด์ฃผ์๊ธฐ ๋ฐ๋๋๋ค. ํด๋น ํฌ์คํ ์์ ์ด์ ๊ธ์ ๋ด์ฉ์ ๋ชจ๋ ์ดํดํ๊ณ ์๋ค๋ ์ ์ ํ์ ํฌ์คํ ์ ์งํํฉ๋๋ค.
์ด๋ฒ์๋ cert-manager๋ฅผ ์ด์ฉํด์ tomcat ํต์ ์ ์ํธํ ํด๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค. "์ด์ ์ MySQL์ ์ํธํํ๋ ๊ฒ์ฒ๋ผ ์ฝ๊ฒ secret ํ์ผ ์ ์ฉํ๋ฉด ๋๋ ๊ฑฐ ์๋?!"๋ผ๊ณ ์๊ฐํ์ค ์๋ ์์ง๋ง, ์ด์ ๊ณผ ์กฐ๊ธ ๋ค๋ฅธ ๋ถ๋ถ์ด ์์ต๋๋ค. ์ด์ ์ ์ฌ์ฉํ๋ Certificate yaml ํ์ผ(์๋์ ์ฝ๋)์ ๋ณด๋ฉด keyEncoding ๊ฐ์ด pkcs1๋ก ๋์ด์ ธ ์๋ ๊ฒ์ ํ์ธํ์ค ์ ์์ต๋๋ค.
์ฌ๊ธฐ์ PKCS๋ ๊ณต๊ฐํค ๊ธฐ๋ฐ๊ตฌ์กฐ์์ ์ธํฐ๋ท์ ์ด์ฉํด ์์ ํ๊ฒ ์ ๋ณด๋ฅผ ๊ตํํ๊ธฐ ์ํ ์ ์กฐ์ฌ๊ฐ ํ๋กํ ์ฝ๋ก RSA๊ฐ ๊ฐ๋ฐํ ์ํธ ์์ฑ ์์คํ ์ ๋๋ค. cert-manager์์๋ ๊ธฐ๋ณธ์ ์ผ๋ก default key encoding ๊ฐ์ธ PKCS#1๊ณผ PKCS#8๋ง์ ์ง์ํฉ๋๋ค. ๊ทธ๋ฆฌ๊ณ Spring์์ PKCS#11๊ณผ PKCS#12๋ง์ ์ง์ํ๊ณ ์์ต๋๋ค. ์ ์ด์ ๋ฌด์์ด ๋ฌธ์ ์ธ์ง ์์๊ฒ ๋์...?
์ฐ๋ฆฌ๊ฐ ๋ง๋ secret ํ์ผ์ PKCS#1 ์ธ์ฝ๋ฉ์ด๊ธฐ ๋๋ฌธ์ spring์ ์ ์ฉํ๊ธฐ์ ์๋ง์ง ์์ต๋๋ค. ๋ฐ๋ผ์ ์ถ๊ฐ์ ์ผ๋ก ๋ณํ์ ํด์ฃผ๊ฑฐ๋ cert-manager์์ ์ ๊ณตํ๋ ๋ค๋ฅธ ๊ธฐ๋ฅ์ ์ฌ์ฉํด์ผ ํฉ๋๋ค. ํด๋น ํฌ์คํ ์์ ์ด ๋ ๊ฐ์ง ๋ฐฉ๋ฒ์ ๋ชจ๋ ์ดํด๋ณด๊ณ ์ cert-manager์์ PKCS#1๊ณผ PKCS#8๋ง์ ์ง์ํ๋์ง ์์๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
โ ๏ธ ํด๋น ํฌ์คํ ์ ์์ ๋ ์ด์ ํฌ์คํ ์ ์ฐธ๊ณ ํ์ฌ secret ๋ฆฌ์์ค๊ฐ Spring Boot deployment์ ์ฃผ์ ๋์ด ์๋ค๊ณ ๊ฐ์ ํ๊ณ ์งํํ๊ฒ ์ต๋๋ค.
# ์ด์ ํฌ์คํ
์์ ์ฌ์ฉํ๋ Certificate yamlํ์ผ
apiVersion: cert-manager.io/v1alpha2
kind: Certificate
metadata:
name: selfsigned-cert
namespace: default
spec:
secretName: selfsigned-cert-tls
duration: 2880h # 120d
renewBefore: 360h # 15d
commonName: Selfsigned certificate
isCA: false
keySize: 4096
keyAlgorithm: rsa
keyEncoding: pkcs1
usages:
- digital signature
- key encipherment
- server auth
issuerRef:
name: selfsigned-issuer
kind: ClusterIssuer
group: cert-manager.io
๐ ์ ํ๋ฆฌ์ผ์ด์ ๋ด์์ Encoding ๋ณํํ๊ธฐ
์ฒซ ๋ฒ์งธ ๋ฐฉ๋ฒ์ผ๋ก Spring Boot ์ ํ๋ฆฌ์ผ์ด์ ๋ด์์ PKCS#1 ์ธ์ฝ๋ฉ ๋ key๋ค์ PKCS#12๋ก ๋ณํํด์ ์ฌ์ฉํ๋๋ก ํ๊ฒ ์ต๋๋ค. ๋จผ์ ์ด์ ํ์ํ dependency๋ฅผ ์ถ๊ฐํ๋๋ก ํ๊ฒ ์ต๋๋ค. ํด๋น ์์์์ maven ๊ธฐ๋ฐ์ผ๋ก ์์๋ฅผ ์งํํ๊ฒ ์ต๋๋ค.
// poam.xml
<dependency>
<groupId>de.dentrassi.crypto</groupId>
<artifactId>pem-keystore</artifactId>
<version>2.2.0</version> <!-- check for most recent version -->
</dependency>
ctron/pem-keystore
A PKCS #1 PEM KeyStore for Java. Contribute to ctron/pem-keystore development by creating an account on GitHub.
github.com
dependency๋ฅผ ์ถ๊ฐํ์ผ๋ฉด ์๋์ ๊ฐ์ด PemKeyStoreProvider๋ฅผ ์ถ๊ฐํด์ค๋๋ค.
import de.dentrassi.crypto.pem.PemKeyStoreProvider;
…
public static void main(final String[] args) throws Exception {
Security.addProvider(new PemKeyStoreProvider());
SpringApplication.run(Application.class, args);
}
๊ทธ๋ฐ ๋ค์ keystore.properties์ ์ฃผ์ ๋ฐ์ key๋ค์ ์ ๋ ฅํด ์ค ๋ค์, application.properties์์ ์๋์ ๊ฐ์ด classpath๋ฅผ ์ง์ ํด์ฃผ๋ฉด SSL ์ ์ฉ์ด ์๋ฃ๋ฉ๋๋ค.
# keystore.properties
alias=keycert
source.key=/etc/tomcat/tls/tls.key
source.cert=/etc/tomcat/tls/tls.crt
# application.properties
server.ssl.key-store-type=PEMCFG.MOD
server.ssl.key-store=classpath:keystore.properties
server.ssl.key-password=
server.ssl.key-alias=keycert
๐ Cert-manager๋ก jks ๋๋ PKCS#12 keystore ๋ง๋ค๊ธฐ
๋ค์์ cert-manager ๋จ์์ Spring์์ ์ฌ์ฉํ ์ ์๋๋ก jks๋ PKCS#12๋ก ์ด๋ฃจ์ด์ง keystore๋ฅผ ๋ง๋๋ ๋ฐฉ๋ฒ์ ๋๋ค.
"์กฐ๊ธ ์ ์ PKCS#12 ์ธ์ฝ๋ฉ์ ์ง์ํ์ง ์๋๋ค๊ณ ํ์ผ๋ฉด์ ๋ฌด์จ ์๋ฆฌ์ง?" ๋ผ๋ ์๊ฐ์ด ๋์ค ์ ์๋๋ฐ, ์ ํํ ๋ง์๋๋ฆฌ๋ฉด PKCS#12 ์ธ์ฝ๋ฉ์ ์ง์ํ์ง ์๋๋ฐ PKCS#12๋ก ์ธ์ฝ๋ฉ๋ keystore ํ์ผ์ ๋ง๋ค ์ ์์ต๋๋ค.
์ ๊ตณ์ด ์ด๋ ๊ฒ ์ง์ ํ๋๋๋ผ๋ ์๋ฌธ์ด ๋์ค ์ ์๋๋ฐ ๊ทธ๊ฑด cert manager๊ฐ ๋ด๋ถ์ ์ผ๋ก golang์ ์ด์ฉํ์ฌ ์ธ์ฆ์๋ฅผ ์์ฑํ๊ณ ์๊ธฐ ๋๋ฌธ์ ๊ทธ๋ ์ต๋๋ค.
์ฐ์ JKS์ Keystore์ ๋ํด ๋ชจ๋ฅด๋ ๋ ์๋ฅผ ์ํด JKS์ Keystore์ ๋ํด์ ์ดํด๋ณด๊ณ ์ด ๋ฌธ์ ์ ๋ํด ์ด์ผ๊ธฐ๋ฅผ ์ด์ด๊ฐ๋๋ก ํ๊ฒ ์ต๋๋ค.
๐ค JKS์ Keystore์ ์ฐจ์ด์ ์ด ๋ญ๊ฐ์?
JKS๋ Java Key Store์ ์ฝ์์ด๊ณ ์๋ฐ ๋ด์์ ์ฌ์ฉํ๋ keystore์ ๋๋ค. ๊ทธ๋ฆฌ๊ณ keystore๋ ์ธ์ฆ์, ๋น๋ฐ ํค ๋ฑ์ ์ปจํ ์ด๋์ ๋๋ค. ์ฆ ์ฐ๋ฆฌ๊ฐ ์ด์ ํฌ์คํ ์์ ๋ง๋ค์๋ secret ํ์ผ์ ๋ฐ์ดํฐ๋ค์ด ์ปจํ ์ด๋ ํน์ ๊ฐ์ฒด์ฒ๋ผ ์์ฑ๋ ํ์ผ์ด๋ผ๊ณ ์๊ฐํ์๋ฉด ํธํ ๊ฒ ๊ฐ์ต๋๋ค.
์ด ๋์ ๋จ์ํ ํค ์ ์ฅ์์ ์ ํ์ ์ฐจ์ด์ผ ๋ฟ ํฐ ์ฐจ์ด๋ ์์ต๋๋ค.
์ข ๋ ์์ธํ ๋ด์ฉ์ ์๋์ URL์์ ํ์ธํฉ๋๋ค.
Difference between .keystore file and .jks file
I have tried to find the difference between .keystore files and .jks files, yet I could not find it. I know jks is for "Java keystore" and both are a way to store key/value pairs. Is there any
stackoverflow.com
๊ทธ๋ผ ๊ณ์ํด์ ์ด์งธ์ KeyEncoding์ PKCS#1๊ณผ PKCS#8์ ์ง์ํ๋ฉด์ ์ PKCS#12๋ jks๋ keystore๋ง์ ์ง์ํ๋์ง ์์๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค. ํด๋น ๋ฌธ์ ์ ๊ดํด์๋ cert-manager์ ๋ด๋ถ ๊ตฌํ ์ฝ๋๋ฅผ ํ์ธํ๋ฉด ์ ์ ์์ต๋๋ค.
์๋์ ์ฝ๋๋ cert manager์ ์ฝ๋(114๋ฒ์งธ ๋ผ์ธ)๋ฅผ ๋ฐ์ทํ ๊ฒ์ ๋๋ค.
// the type of key encoding and then inspecting the type of key provided.
// It only supports encoding RSA or ECDSA keys.
func EncodePrivateKey(pk crypto.PrivateKey, keyEncoding v1.PrivateKeyEncoding) ([]byte, error) {
switch keyEncoding {
case v1.PrivateKeyEncoding(""), v1.PKCS1:
switch k := pk.(type) {
case *rsa.PrivateKey:
return EncodePKCS1PrivateKey(k), nil
case *ecdsa.PrivateKey:
return EncodeECPrivateKey(k)
default:
return nil, fmt.Errorf("error encoding private key: unknown key type: %T", pk)
}
case v1.PKCS8:
return EncodePKCS8PrivateKey(pk)
default:
return nil, fmt.Errorf("error encoding private key: unknown key encoding: %s", keyEncoding)
}
}
// EncodePKCS1PrivateKey will marshal a RSA private key into x509 PEM format.
func EncodePKCS1PrivateKey(pk *rsa.PrivateKey) []byte {
block := &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(pk)}
return pem.EncodeToMemory(block)
}
// EncodePKCS8PrivateKey will marshal a private key into x509 PEM format.
func EncodePKCS8PrivateKey(pk interface{}) ([]byte, error) {
keyBytes, err := x509.MarshalPKCS8PrivateKey(pk)
if err != nil {
return nil, err
}
block := &pem.Block{Type: "PRIVATE KEY", Bytes: keyBytes}
return pem.EncodeToMemory(block), nil
}
ํด๋น ์ฝ๋๋ฅผ ์ดํด๋ณด๋ฉด x509.MarshalPKCS1PrivateKey() ์ ๊ฐ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ(go์ธ์ด ์์ฒด๋ก ๋ด์ฅํ๊ณ ์๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋๋ค.)๋ฅผ ํธ์ถํด์ PKCS#1๊ณผ PKCS#8์ ํค๋ฅผ ์์ฑํ๋ ๊ฒ์ ๋ณผ ์ ์์ต๋๋ค.
๋ฐ๋ฉด PKCS#12์ ๊ดํด์๋ ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์์ ์ง์ํด์ฃผ์ง ์๊ธฐ ๋๋ฌธ์ cert manager๋ pkcs12 ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํฉ๋๋ค.
์ keyEncoding ๊ฐ์ ๋ฐ๋ผ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅด ๊ตฌ๋ถํด๋์ง๋ ์ ๋ชจ๋ฅด๊ฒ ์ง๋ง... (ํน์ ์๋ค๋ฉด ์๋ ค์ฃผ์ธ์ ๐ญ) cert manager๊ฐ key encoding ๊ฐ์ ๋ฐ๋ผ certificate๋ฅผ ๋ค๋ฅด๊ฒ ์์ฑํ๋ ์ด์ ์ ๋ํด์๋ ์ ์ ์์์ต๋๋ค.
๐ง๐ป๐ปJKS๋ฅผ ์ด์ฉํด์ Spring์ HTTPS ์ ์ฉํ๊ธฐ
์๋ก ์ด ๊ธธ์์ต๋๋ค๋ง... ์ด์ฐ์ด์ฐ cert-manager์์ JKS์ Keystore๋ฅผ ์ ๋ฐ๋ก ์ง์ํ๋์ง๋ฅผ ์์์ผ๋ ํด๋น ๊ธฐ๋ฅ์ ์ฌ์ฉํด์ tomcat์ HTTPS๋ฅผ ์ ์ฉํด๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค. ํด๋น ํฌ์คํ ์์ JKS๋ฅผ ์ด์ฉํ๋๋ก ํ๊ฒ ์ต๋๋ค. (๋ฐฉ๋ฒ์ด ํฌ๊ฒ ๋ค๋ฅด์ง ์์ต๋๋ค. ์ต์ ํ๋ ์ฐจ์ด.)
๊ทธ๋ฌ๊ธฐ ์ํด์ ๋จผ์ JKS ํ์ผ์ ๋น๋ฐ๋ฒํธ๋ฅผ ๋ถ์ฌํด์ฃผ๊ธฐ ์ํ secret ํ์ผ ํ๋๋ฅผ ์์ฑํ๋๋ก ํ๊ฒ ์ต๋๋ค. ์ด ํ์ผ์ ์ด์ฉํด์ ์ฐ๋ฆฌ๋ JKS์ ๋น๋ฐ๋ฒํธ๋ฅผ ๋ถ์ฌํ๊ฒ ๋ฉ๋๋ค.
secret์ ์์ ํฌํจํ๊ณ ์๋ ๋ฐ์ดํฐ๋ฅผ base64๋ก ์ธ์ฝ๋ฉํด์ ๋ฃ์ด์ผ ํฉ๋๋ค. (์์ธํ ๋ด์ฉ์ ์ฌ๊ธฐ๋ฅผ ์ฐธ์กฐํ์ธ์.) ํด๋น ์์์์ password๋ฅผ ํธ์๋ฅผ ์ํด "1234"๋ก ์ง์ ํ๋๋ก ํ๊ฒ ์ต๋๋ค. ๊ทธ๋ฆฌ๊ณ ์ด password๋ฅผ ์ด์ฉํด์ secret์ ๋ง๋ค๊ธฐ ์ํด์ ๋จผ์ base64 ๊ฐ์ผ๋ก ๋ณํํ๋๋ก ํ๊ฒ ์ต๋๋ค.
์ด์ ๋ณํํ ๊ฐ์ ์ด์ฉํด์ secret ํ์ผ์ ๋ง๋ญ๋๋ค.
# jks-password-secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: jks-password-secret
namespace: default
type: Opaque
data:
password-key: MTIzNA== # 1234
๊ทธ๋ฐ ๋ค์ ํด๋น ํค ๊ฐ์ ์ด์ฉํด์ Certificate๋ฅผ ๋ง๋ค์ด๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
โ ๏ธํด๋น ํฌ์คํ ์์ ์ด์ ํฌ์คํ ์ ํตํด์ ClusterIssuer๊ฐ ์์ฑ๋์ด์ ธ ์๋ค๊ณ ๊ฐ์ ํฉ๋๋ค.
# selfsigned-jks.yaml
apiVersion: cert-manager.io/v1alpha2
kind: Certificate
metadata:
name: selfsigned-jks
namespace: noah-test
spec:
secretName: selfsigned-cert-jks
duration: 2880h # 120d
renewBefore: 360h # 15d
commonName: ooeunz.tistory.com
isCA: false
keySize: 2048
keyAlgorithm: rsa
keyEncoding: pkcs1
keystores:
jks:
create: true
passwordSecretRef: # Password used to encrypt the keystore
key: password-key
name: jks-password-secret
usages:
- digital signature
- key encipherment
- server auth
issuerRef:
name: selfsigned-issuer
kind: ClusterIssuer
group: cert-manager.io
spec.keystores.passwordSecretRef๋ฅผ ๋ณด์๋ฉด name์ ๋ฐฉ๊ธ ์์ฑํ secret์ ์ด๋ฆ์ ์ง์ ํ๊ณ key์ jks-password-secret.yaml์์ ๋ฃ์ key๊ฐ์ด ๋ค์ด๊ฐ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค. ํด๋น ๋ฐ์ดํฐ๋ฅผ jks์ password๋ก ์ฌ์ฉํ๊ฒ ๋ค๋ ๋ป์ผ๋ก, spring์์ ํด๋น jks๋ฅผ ์ฌ์ฉํ ๋ ์๊น ์ ๋ ฅํด๋ ํจ์ค์๋๋ฅผ ์ฌ์ฉํ๊ฒ ๋ฉ๋๋ค.
โ ๏ธ๋ง์ฝ jks๊ฐ ์๋๋ผ keystore๋ฅผ ์ฌ์ฉํ๊ณ ์ถ๋ค๋ฉด jks๊ฐ ์๋ pkcs12๋ฅผ ๋ฃ์ด์ฃผ์๋ฉด ๋ฉ๋๋ค.
์ด์ ๋ชจ๋ ์ค๋น๊ฐ ๋๋ฌ์ต๋๋ค. ์๊น์ ๊ฐ์ด ์๋ก ๋ง๋ secret ํ์ผ์ deployment์ ์ฃผ์ ์์ผ ์ค๋๋ค. ๊ทธ๋ฐ ๋ค์, ์ด๋ฒ์๋ application.properties๋ง ์๋์ ๊ฐ์ด ๋ณ๊ฒฝํด์ค๋๋ค.
# application.properties
server.ssl.enabled=true
server.ssl.key-store=/etc/tomcat/tls/keystore.jks
server.ssl.key-store-password=1234
์กฐ๊ธ ๋ ์ฌ๊ฒจ ๋ณผ ๋ถ๋ถ์, server.ssl.key-store์๋ mount ํด์ค seccret์ ๊ฒฝ๋ก๋ฅผ ์ก์์ฃผ๊ณ server.ssl.key-store-password์ jks-password-secret์ ๋ฃ์ด์ค passrod๋ฅผ ๋ฃ์ด์ค๋ค๋ ์ ์ ๋๋ค.
์ฌ๊ธฐ๊น์ง Spring์์๋ cert-manager๋ฅผ ์ด์ฉํด์ HTTPS๋ฅผ ์ ์ฉํด๋ณด์์ต๋๋ค. ์ด์ธ์๋ ์ด์ ํฌ์คํ ์์ ์ ๊น ์ธ๊ธํ๋ isCa ์ต์ ์ ์ด์ฉํด์ namespace๋ณ๋ก CA๋ฅผ ๋ณ๋๋ก ๊ด๋ฆฌํ๋ ๋ฑ ๋ค์ํ ํ์ฉ ๋ฐฉ๋ฒ์ด ์์ผ๋ ์ฐธ๊ณ ํ์๋ฉด ์ข์ ๊ฒ ๊ฐ์ต๋๋ค.
๋ง์ง๋ง์ผ๋ก ์๋์ URL์์ ํด๋น ํฌ์คํ ์์ ์ฌ์ฉํ ์ฝ๋๋ฅผ ํ์ธํ์ค ์ ์์ต๋๋ค. ๐
ooeunz/blog-code
Contribute to ooeunz/blog-code development by creating an account on GitHub.
github.com
'DevOps > Cert manager' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[Cert manager] Kubernetes ํต์ ์ํธํ ๋ฐ ์๋ํ (MySQL HTTPS ์ ์ฉ) (0) | 2021.02.05 |
---|