This service is meant to run as a sidecar to the Apigee hybrid API gateway (also known as Message Processor). The service takes a Google Cloud Service Account as a parameter and is used to encrypt or decrypt text using Cloud KMS. The service can also store and retrieve data from GCP Secret Manager.
This service is meant to be used with the Apigee hybrid API Runtime. When developing API Proxies on Apigee, a developer may want to encrypt or decrypt parts of the payload. Google Cloud provides Cloud KMS. The services uses Cloud KMS libraries to encrypt or decrpyt data.
Sensitive information often needs to be stored in a secure location. GCP Secret Manager provides a service (like a vault) to store sensitive information.
- Apigee hybrid runtime installed on GKE or GKE on-premises (v1.13.x)
- A GCP Project with Cloud KMS and Secret Manager APIs enabled
- A Service Account with the following roles: a. Cloud KMS CryptoKey Encrypter/Decrypter b. Secret Manager Admin c. Secret Manager Secret Accessor d. Cloud KMS CryptoKey Public Key Viewer
- kubectl 1.13 or higher
- docker 19.x or higher (if not using skaffold)
- skaffold 1.1.0 or higher (optional)
- Build the docker image
docker build -t gcr.io/{project-id}/cloudkms-encryption
- Push to a container registry
docker push gcr.io/{project-id}/cloudkms-encryption
- Modify the kubernetes manifest
kubectl create secret -n {namespace} generic cloudkms-encryption-svc-account --from-file client_secret.json
kubectl apply -n {namespace} -f cloudkms-encryption.yaml
This application can also be installed via skaffold. Modify the skaffold.yaml to set the appropriate project name.
skaffold run
When rerunning/installing the application, you may observe errors like this:
- Error from server (Invalid): error when applying patch:
...
...
`selector` does not match template `labels`
There is an open issue for this in the skaffold project.
Workaound: first run skaffold delete
and then skaffold run
The following environment variables are mandatory:
GOOGLE_APPLICATION_CREDENTIALS
- Path to service account jsonPROJECT_ID
- GCP project idREGION
- Crypto key regionKEY_RING
- Crypto key ringSYM_CRYPTO_KEY
- Symmaetric key nameASYM_CRYPTO_KEY
- Assymetric key name
Path: /encrypt
Method: POST
Accept: text/plain
Content-Type: application/json
The response is base64 encoded
curl 0.0.0.0:8080/encrypt -d 'sample clear text data'
Output:
< HTTP/1.1 200 OK
< Content-Type: application/json; charset=UTF-8
<
{"payload":"CiQATxZWh3Ky1nUed8+Uzfy1rrZ0hUrvt8J0OZUyauXbrvv2TwwSLwCPcW8BdQBpa9PXMWdOUk1c8SLNPG7J4NCyVXNfF8FLBnhgXYMGNCeY4B0673bf"}
Path: /decrypt
Method: POST
Accept: text/plain
Content-Type: application/json
curl 0.0.0.0:8080/decrypt -d 'CiQATxZWh3Ky1nUed8+Uzfy1rrZ0hUrvt8J0OZUyauXbrvv2TwwSLwCPcW8BdQBpa9PXMWdOUk1c8SLNPG7J4NCyVXNfF8FLBnhgXYMGNCeY4B0673bf'
Output:
< HTTP/1.1 200 OK
< Content-Type: application/json; charset=UTF-8
<
{"payload":"sample clear text data"}
Path: /asmencrypt
Method: POST
Accept: text/plain
Content-Type: application/json
The response is base64 encoded
curl localhost:8080/asmencrypt -H "Content-Type: text/plain" -d 'this is a test'
Output:
{"payload":"27dWLYAtq3tI7E3ukT5++9vEoevbb+r3uDB/CqeWxt7JrFtcoy4EMurcnhyVbsDjd7AwYB3icxs/ETEGmrxFESOR8xOI7vE2kCG+8xlFbMitIQDRsmuCwRNMyYfQMyUPtvN+eQ9YJmpxo7YqprOCk3OQ4PDew9R4VAVJxUurGbjNW5gvzLSfutqyR5y7/Ey54HRlNZCWD7GkHHi1YTIp/oc0VL9yr4K8D6P16aH4lF2H0qBF1dOGJCK19ArAZeRwPCauETdGgWepsB9BJIAvsH2CCgOGkACQHgYFIWoBCGW8CEONrlsWh455KctcZ7s4DfMI0YhTsPhu6OLpDbsTsQ=="}
Path: /asmdecrypt
Method: POST
Accept: text/plain
Content-Type: application/json
curl localhost:8080/asmdecrypt -H "Content-Type: text/plain" -d '27dWLYAtq3tI7E3ukT5++9vEoevbb+r3uDB/CqeWxt7JrFtcoy4EMurcnhyVbsDjd7AwYB3icxs/ETEGmrxFESOR8xOI7vE2kCG+8xlFbMitIQDRsmuCwRNMyYfQMyUPtvN+eQ9YJmpxo7YqprOCk3OQ4PDew9R4VAVJxUurGbjNW5gvzLSfutqyR5y7/Ey54HRlNZCWD7GkHHi1YTIp/oc0VL9yr4K8D6P16aH4lF2H0qBF1dOGJCK19ArAZeRwPCauETdGgWepsB9BJIAvsH2CCgOGkACQHgYFIWoBCGW8CEONrlsWh455KctcZ7s4DfMI0YhTsPhu6OLpDbsTsQ=='
Output:
{"payload":"this is a test"}
Creates a new secret in Secret Manager.
Path: /secrets
Method: POST
Accept: application/json
Content-Type: application/json
curl localhost:8080/secrets -H "Content-Type: application/json" -d '{"secretId":"test"}'
Stores a secret in Secret Manager, optionally encrypts and stores a section in Secret Manager
Path: /storesecrets
Method: POST
Accept: application/json
Content-Type: application/json
curl localhost:8080/storesecrets -H "Content-Type: application/json" -d '{"secretId":"test","payload":"test data"}'
The same method can be used to encrypt first with Cloud KMS and then store in Secret Manager.
{
"secretId":"test",
"payload":"test data",
"encrypted": true
}
Access a secret in Secret Manager, optionally decrypts the secret first and retrieves in clear text
Path: /secrets/{secretName}/{version}
Method: GET
Accept: application/json
Content-Type: application/json
curl localhost:8080/secrets/test/1
The same method can be used to access the data from Secret Manager and them decrypt with Cloud KMS
curl localhost:8080/secrets/test/1?ecrypted=true
A typical pattern/example would be to use a Service Callout policy to access operations supported by the service.