Key Management Service
키 사양
사용방법
Spring Kotling Example
dependencies {
implementation("software.amazon.awssdk:kms:2.23.7")
implementation("software.amazon.awssdk:sdk-core:2.23.7")
}
package com.fastfive.booking.application
import org.springframework.beans.factory.annotation.Value
import org.springframework.stereotype.Component
import software.amazon.awssdk.core.SdkBytes
import software.amazon.awssdk.services.kms.KmsClient
import software.amazon.awssdk.services.kms.model.DecryptRequest
import software.amazon.awssdk.services.kms.model.EncryptRequest
import software.amazon.awssdk.services.kms.model.EncryptionAlgorithmSpec
import java.nio.charset.StandardCharsets
import java.util.*
@Component
class KmsService(val kmsClient: KmsClient, @Value("\\${aws.kms.symmetric}") val keyId: String) {
fun encrypt(plainText: String): String {
val request = EncryptRequest.builder()
.keyId(keyId)
.plaintext(SdkBytes.fromString(plainText, StandardCharsets.UTF_8))
.encryptionAlgorithm(EncryptionAlgorithmSpec.SYMMETRIC_DEFAULT)
.build()
val encryptResponse = kmsClient.encrypt(request)
val encode = Base64.getEncoder().encode(encryptResponse.ciphertextBlob().asByteArray())
return String(encode, StandardCharsets.UTF_8)
}
fun decrypt(encryptedText: String): String {
val decode = Base64.getDecoder().decode(encryptedText)
val decryptRequest = DecryptRequest.builder()
.keyId(keyId)
.ciphertextBlob(SdkBytes.fromByteArray(decode))
.encryptionAlgorithm(EncryptionAlgorithmSpec.SYMMETRIC_DEFAULT)
.build()
val decryptResponse = kmsClient.decrypt(decryptRequest)
val plaintext = decryptResponse.plaintext().asByteArray()
return String(plaintext, StandardCharsets.UTF_8)
}
}
@Bean
fun customJwtDecoder(kmsClient: KmsClient): JwtDecoder {
return JwtDecoder { token: String? ->
val signedJwt = SignedJWT.parse(token)
val header = "${signedJwt.header}"
val payload = "${signedJwt.payload}"
val signature = signedJwt.signature.decode()
val fromByteArray = Base64Utils.encodeToString(header, payload)
val kmsVerifyRequest = VerifyRequest.builder()
.keyId(asymmetric)
.message(fromByteArray)
.signature(SdkBytes.fromByteArray(signature))
.signingAlgorithm(SigningAlgorithmSpec.ECDSA_SHA_256)
.build()
val verifyResponse = kmsClient.verify(kmsVerifyRequest)
val headers = LinkedHashMap(signedJwt.header.toJSONObject())
val claims = MappedJwtClaimSetConverter.withDefaults(emptyMap())
.convert(signedJwt.jwtClaimsSet.claims) as Map<String, Any>
Jwt.withTokenValue(token)
.headers { h -> h.putAll(headers) }
.claims { c -> c.putAll(claims) }
.build()
}
}
@Bean
fun customJwtEncoder(kmsClient: KmsClient, objectMapper: ObjectMapper): JwtEncoder {
return JwtEncoder { parameters: JwtEncoderParameters? ->
if (parameters == null) throw IllegalArgumentException("parameters cannot be null")
val jwsHeader = parameters.jwsHeader ?: JwsHeader.with(SignatureAlgorithm.ES256).build()
val claims = parameters.claims
val header = objectMapper.writeValueAsString(jwsHeader.headers)
val payload = objectMapper.writeValueAsString(claims.claims)
val fromByteArray = Base64Utils.encodeToString(header, payload)
val signRequest = SignRequest.builder()
.keyId(asymmetric)
.messageType(MessageType.RAW)
.message(fromByteArray)
.signingAlgorithm(SigningAlgorithmSpec.ECDSA_SHA_256)
.build()
val signResponse: SignResponse = kmsClient.sign(signRequest)
val headers = Base64Utils.encodeToBase64String(header.toByteArray())
val payloads = Base64Utils.encodeToBase64String(payload.toByteArray())
val signature = Base64Utils.encodeToBase64String(signResponse.signature().asByteArray())
val tokenValue = "$headers.$payloads.$signature"
Jwt(tokenValue, claims.issuedAt, claims.expiresAt, jwsHeader.headers, claims.claims)
}
}