terraform을 사용하다보면 password 같은 비밀데이터를 암호화가 되지 않거나 base64로만 인코딩해서 gitgub에 올리는 경우가 많습니다.
누군가가 이 내용을 탈취하게 된다면 그대로 비밀 데이터가 노출되게 됩니다.
물론 private repo에 있기에 문제 없다고 생각할 수도 있지만 좀 더 대비를 해서 공격을 당해도 안전하게 유지를 한다면 더 좋지 않을까요?
그렇다면 비밀 데이터를 어떻게 관리를 하면 좋을까요?
terraform에서는 rsadecrypt라는 함수가 있습니다. 이 함수는 rsa 기반으로 활용해서 데이터를 복호화를 해주며 base64로 encoding된 문자열을 인자로 받습니다.
해당 함수는 rsa를 사용하고 있기에 비대칭키를 사용하게 됩니다. 비대칭키 알고리즘에 경우, public key와 private key 두 개가 다 필요하기
때문에 보안에 안정적입니다. 반면 대칭키 알고리즘에에 경우 대칭키 하나가 유출되면 모든 값을 다 바꿔줘야 합니다.
(kubernetes sealed-secret에 경우도 위와 유사한 방식으로 암호화를 진행합니다.)
예시)
rsadecrypt("OR3W62/MhuX6rI3vaFdnOnvembiVFA8fXZQWXV84Qahk7HBePnbad5g+voN+CIO1RdT6bIvjXmGLSnYR4HPg6X98mtAWASKMQYPUcHUxrmA0KXtvUne8EF1fW6PQmyktAr7/I1Z6ssfejnxG2XHCGtjoGd3Drf4S8bkR2GW+gttWjvr1H2uQsvgEVV3jWeXfVcZcwzRt2t8Ydzp9k7eDz8ctIvPjeRgOALZjeKoPJB0JW4IObI2508k142sPtmcrFmVmgCNe/XX6T5hNFZt+5ejIx8izNbk/bRw5csqO7XPNZA4Bag7HA+2m5BFb6YwOj34fgFlgoNrGXoJ4T6Ff4A=="
, file("/home/ubuntu/private.pem"))
rsadecrypt를 사용하기 위해서는 다음과 같은 절차가 필요합니다.
1. private key 관리하기 -> private key를 local에서 관리하거나 server에 추가해두기
2. public key를 terraform 사용자들에게 공유해주고 암호화해서 terraform 코드에 적용하기
위 두가지 절차를 통해 rsadecrypt를 사용할 수 있게 됩니다.
decrypt 방법에 대해서만 설명을 했는데 그렇다면 어떻게 encrypt를 만들면 좋을까요?
저는 golang을 활용해서 cli를 만들어서 공유를 했었습니다.
아래와 같이 publicKey를 embeding했습니다.
embeding을 해서 주게되면 일반적으로 다른 개발자는 해당 key를 받아야 하거나 할 필요가 없기에 좀 더 편하게 사용할 수 있어서
사용했습니다.
package main
import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
_ "embed"
"encoding/base64"
"encoding/pem"
"fmt"
"os"
)
//go:embed public.pem
var publicKey string
func main() {
if len(os.Args) < 2 {
fmt.Println("data is required")
return
}
value, err := encrypt(os.Args[1])
if err != nil {
fmt.Println(err)
return
}
fmt.Println(value)
}
// Encrypt encrypts the given data with the given key.
func encrypt(data string) (string, error) {
publicKeyPEM := []byte(publicKey)
publicKeyBlock, _ := pem.Decode(publicKeyPEM)
publicKey, err := x509.ParsePKIXPublicKey(publicKeyBlock.Bytes)
if err != nil {
return "", err
}
plaintext := []byte(data)
ciphertext, err := rsa.EncryptPKCS1v15(rand.Reader, publicKey.(*rsa.PublicKey), plaintext)
if err != nil {
return "", err
}
encodedString := base64.StdEncoding.EncodeToString(ciphertext)
return encodedString, nil
}
아래 명령어를 통해서 값을 받을 수 있습니다.
> go run main.go hello
RtKLXG3nqniCButXgc5cHuDAIdB9ntBfkcQWgXVg274J2LRN3YM7icuHz5ngabQTKLC9oVRqOpsiNTEKjMJydbDBtKDfVLQq2PPFSC8g0ejptsbkr0kVryYGUEtXI3ks0c7XtVgyIGIwIvxCpAsJJaHUkL7OU1cpAc1DL7jXz/nui7HCdszx4Z0M4Lq3vGxCA9FPZZ+Nm6IN9MbXqLlvfRgZ2mYqxcFNQgF7+8VZct5mF13ELd2sVyAT+xK1m+ytwPPK0pT/6FPGXwn6t1w5F2d7xxkOqk6EiaKzxgz8ZHPrbf5eBZji9BUXS9RT1j1odEu4gM/pCiXGnUUB/doZnA==
이제 이 코드들을 활용해서 비밀데이터를 관리해보시면 좋을거 같습니다.