Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Kamus example #39

Merged
merged 13 commits into from Dec 27, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
60 changes: 44 additions & 16 deletions README.md
Expand Up @@ -5,24 +5,52 @@ The encryption is done using strong encryptiong providers (currently supported:

## Getting Started

The simple way to run Kamus is by using the Helm chart.
The simple way to run Kamus is by using the Helm chart:
```
helm upgrade --install incubator/kamus
```
Reffer to the installation guide for more details.
After installing Kamus, you can start using it to encrypt secrets.
Before encrypting a secret, you will need a Kubernetes service account.
The service account is used to authenticate your application in production.
Only applications tha tare running with this service account, will be able to decrypt the secret.
After create the service account, use the following HTTP request to encrypt your secret:
Kamus encrypt secrets for a specific application, represent by a [Kubernetes Service Account](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-accoun).
Creat a service account for your application, and mount it on the pods running your application.
Now, when you know the name of the service account, and the namespace it exist in, use Kamus CLI to encrypt the secret:
```
POST /api/v1/encrypt HTTP/1.1
Host: <Kamus Server URL>
Content-Type: application/json
Cache-Control: no-cache
{
"data": "super secret",
"service-account": "<name of service account>",
"namespace": "<name of your namespace>"
}
kamus-cli encrypt super-secret kamus-example-sa default --kamus-url <Kamus URL>
```
Pass the value returned by the CLI to your pod, and use Kamus Decrypt API to decrypt the value.
The simplest way to achieve that is by using the init container.
An alternative is to use Kamus decrypt API directly in the application code.
To make it clearer, take a look on a working [example app](example/README).
You can deploy this app to any Kubernetes cluster that has Kamus installed, to understand how it works.

## Architecture
Kamus has 3 components:
* Encrypt API
* Decrypt API
* Key Management System (KMS)

The encrypt and decrypt API handling encryption and decryption requests.
The KMS is a wrapper for various cryptographic solutions. Currently supported:
* AES - using one key for all secrets
* Azure KeyVault - create one key per service account.
We look forward to add support for other cloud solutions, like AWS KMS.
If you're interested in such a failure, please let us know.
We would like help with testing it out.
Consult the [installation guide](docs/install.md) for more details on how to deploy Kamus using the relevant KMS.

### Utilities
Kamus shipped with 2 utilities that make it easier to use:
* Kamus CLI - a small CLI that ease the interaction with the Encrypt API. Refer to the docs for more details.
* Kamus init container - a init container that interact with the Decrypt API. Refer to the docs for more details.

Than, use the decryptor init container to decrypt the secret in production.
## Security
We take security seriously at Soluto.
To learn more about the security aspects of Kamus, reffer to the Threat Modeling docs, containing all the various threats and mitigations we discussed.
Before installing Kamus in production, reffer the installation guide to learn the best practices of deploying Kamus securely.
In case you find a security issue, or have something you would like to discuss, reffer to our [Security.md](Security.md) policy.

## Security
## Contributing
Find a bug? Have a missing feature? Please open an issue and let us know.
We would like to help you using Kamus!
Please notice: Do not report security issues on GitHub.
We will delete imediatlly such issues.
6 changes: 4 additions & 2 deletions chart/templates/_helpers.tpl
Expand Up @@ -6,14 +6,16 @@ Expand the name of the chart.
{{- end -}}

{{- define "appsettings.secrets.json" }}
{{ printf "{\n\t\"ActiveDirectory\": { " }}
{{ printf "{" }}
{{ if .Values.keyManagment.azureKeyVault}}
{{ printf "\n\t\"ActiveDirectory\": { " }}
{{ printf "\t\t\"ClientSecret\": \"%s\" " .Values.keyManagment.azureKeyVault.clientSecret }}
{{ printf "} \n"}}
{{- end -}}
{{ if .Values.keyManagment.AES}}
{{ printf "\"KeyManagement\": { \n\t\t\"AES\": { \"Key\": \"%s\" } }" .Values.keyManagment.AES.key }}
{{- end -}}
{{ printf "} \n}"}}
{{ printf "}" }}
{{- end }}

{{- define "common.configurations" -}}
Expand Down
4 changes: 4 additions & 0 deletions chart/values.yaml
Expand Up @@ -55,3 +55,7 @@ autoscale:
targetCPU: 50
envFrom: {}
container: {}
keyManagment:
provider: AESKey
AES:
key: rWnWbaFutavdoeqUiVYMNJGvmjQh31qaIej/vAxJ9G0=
2 changes: 1 addition & 1 deletion cli/encrypt.js
Expand Up @@ -27,7 +27,7 @@ const encrypt = async ({ data, serviceAccount, namespace }, { kamusUrl, allowIns
_logger.log('service account:', serviceAccount);
_logger.log('namespace:', namespace);

if (!allowInsecureUrl && url.parse(kamusUrl).protocol !== "https"){
if (!allowInsecureUrl && url.parse(kamusUrl).protocol !== "https:"){
_logger.error("Insecure Kamus URL is not allowed");
process.exit(1);
}
Expand Down
61 changes: 61 additions & 0 deletions docs/Install.md
@@ -0,0 +1,61 @@
# Installing Kamus
Kamus has an official helm chart, using it is the simplest way to install Kamus:
```
helm upgrade --install incubator/kamus
```
Careful - using this command will deploy Kamus with the default encryption keys.
Meaning, anyone could decrypt the data that Kamus encrypt.
This is fine for testing and playing with Kamus, but not for production installations.
For production usage, please configuration one of the supported KMS.

## AES KMS
AES KMS is the simplest (but less secure) solution.
Kamus will use one strong AES key to encrypt all the data.
Currently, rolling this key is not supported.
To deploy Kamus using AES Key:
* Generate a strong AES key:
```
key=$(openssl rand -base64 32 | tr -d '\n')
```
* Pass the value when deploying kamus, either using `values.yaml` or directly in the helm command:
```
helm upgrade --install kamus incubator/kamus --set keyManager.AES.key=$key
```

## Azure KeyVault KMS
Using [Azure KeyVault](https://azure.microsoft.com/en-us/services/key-vault/) as the key managment solution is a more secure solution.
Azure documentation is far from perfect, so I'm going to reffer to a lot of different guides because there is no one guide documenting the required process.

Start by creating a KeyVault instance.
It is recommend to create a KeyVault with HSM backend for additional security.
Follow this [guide](https://docs.microsoft.com/en-us/azure/key-vault/key-vault-manage-with-cli2#working-with-hardware-security-modules-hsms) for details on how to create a KeyVault using the CLI. It is recommend to protect the KeyVault with firewall, see this [guide](https://docs.microsoft.com/en-us/azure/key-vault/key-vault-network-security) for additional details.

After creating a KeyVault instance, Kamus need permissions to access it.
You grant Kamus permissions by creating an Azure Active Directory application for Kamus, and granting permissions for this application to access the KeyVault created in the previous step.
Creating the required app is covered in 2 parts of the same guide. The [first part](https://docs.microsoft.com/en-us/azure/active-directory/develop/howto-create-service-principal-portal#create-an-azure-active-directory-application) will guide you through the process of creating the app. The [second part](https://docs.microsoft.com/en-us/azure/active-directory/develop/howto-create-service-principal-portal#get-application-id-and-authentication-key) will guide you through the process of creating the client id and client secret, that are used by Kamus for authentication. Try to create the client secret for short period, for example 6 months, and rotate it frequently.

Now you should have 3 objects: KeyVault, client id and client secret. The last part is to grant the application the required permissions on the KeyVault. First we need to get the object id of the application:
```
objectId=$(az ad app show --id <> --output json | jq '.objectId' -r)
```
Now use the following command to grant access:
```
az keyvault set-policy --name <> --object-id $objectId --key-permissions get list create encrypt decrypt
```

Now it's time to deploy Kamus! Use the following settings in your `values.yaml` file:
```
keyManagment:
provider: AzureKeyVault
azureKeyVault:
clientId: <>
clientSecret: <>
keyVaultName: <>
keyType: RSA-HSM //change to RSA if you choosed not to use premium SKU
keySize: 2048
maximumDataLength: 214
```
And now deploy Kamus using the following helm command:
```
helm upgrade --install kamus incubator/kamus -f <path/to/values.yaml>
```
Binary file modified docs/features/assets/images/diagram.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
27 changes: 13 additions & 14 deletions docs/features/assets/images/diagram.pu
@@ -1,28 +1,27 @@
@startuml

actor User
participant EncryptApi
participant KMS
participant DecryptApi
participant Pod
participant Kamus
participant KubernetesApi
participant KMS

== Encryption ==

autonumber
User -> Kamus: Encrypt - data, namespace, service account
Kamus -> KubernetesApi: Get Service Account - namespace, service account
KubernetesApi -> Kamus: Service Account details
Kamus -> KMS: Encrypt - data, namespace, service account
KMS -> Kamus: Enrypted data
Kamus -> User: Enrypted data
User -> EncryptApi: Encrypt - data, namespace, service account
EncryptApi -> KMS: Encrypt - data, namespace, service account
KMS -> EncryptApi: Enrypted data
EncryptApi -> User: Enrypted data

== Decryption ==
autonumber 1
Pod -> Kamus: Decrypt - data, service account token
Kamus -> KubernetesApi: TokenReview - token
KubernetesApi -> Kamus: service account, namespace
Kamus -> KMS: Decrypt - data, service account, namespace
KMS -> Kamus: Decrypted data
Kamus -> Pod: Decrypted data
Pod -> DecryptApi: Decrypt - data, service account token
DecryptApi -> KubernetesApi: TokenReview - token
KubernetesApi -> DecryptApi: service account, namespace
DecryptApi -> KMS: Decrypt - data, service account, namespace
KMS -> DecryptApi: Decrypted data
DecryptApi -> Pod: Decrypted data

@enduml
16 changes: 0 additions & 16 deletions docs/threat-modeling.md

This file was deleted.

53 changes: 53 additions & 0 deletions example/README.md
@@ -0,0 +1,53 @@
# Kamus Example
A small example app, showing the power of Kamus.
Before running this demo, make sure Kamus is up and running, and the CLI is installed.

## Running the demo
Start by encrypting a secret using the CLI:
```
kamus-cli encrypt super-secret kamus-example-sa default --kamus-url <Kamus URL>
```
You might have to pass aditional arguments, based on your installation.

After encrypting the secret, open `deployment-kamus\configmap.yaml`.
Modify the value of `key` to the encrypted value returned from the CLI.

Now, run
```
kubectl apply -f deployment-kamus/
```
To deploy the example app.
Check deployment status using
```
kubectl get pods
```
Notice the `kamus-example` pods. Wait for the pod to be in `Completed` state, and check the logs using
```
kubectl logs -l app=kamus-example
```
You should see the following output
```
{"key":"super-secret"}
```
The example using an init container to decrypt the encrypted values. Checkout the documentation for additional details.

## Kubernetes Secrets
To complete the example, reffer to `deployment-secret`.
This example shows the alternative to Kamus - using Kubernetes native secrets.
Run the demo using
```
kubectl apply -f deployment-kamus/
```
Notice the `kamus-example` pods. Wait for the pod to be in `Completed` state, and check the logs using
```
kubectl logs -l app=kamus-example
```
You should see the following output
```
{"key":"super-secret"}
```
Editing the secrets:
* Open `secret.yaml`
* Decode the value under `config.json` using base64 decoder
* Edit the JSON
* Encode the JSON using base64 encoder, and put this value under `config.json`
2 changes: 2 additions & 0 deletions example/app/Dockerfile
@@ -1,5 +1,7 @@
FROM ruby:2.5-alpine

WORKDIR /example

COPY . .

CMD ["ruby", "hello.rb"]
5 changes: 3 additions & 2 deletions example/app/hello.rb
@@ -1,4 +1,5 @@
require 'json'

config_file = File.read('config.json')
puts config_file
config_file = File.read('/secrets/config.json')
puts config_file

Expand Up @@ -3,5 +3,4 @@ kind: ConfigMap
metadata:
name: encrypted-secrets-cm
data:
key: <encrypted>
key2: <encrypted>
key: 4AD7lM6lc4dGvE3oF+5w8g==:WrcckiNNOAlMhuWHaM0kTw==
Expand Up @@ -4,7 +4,7 @@ metadata:
name: kamus-example
labels:
app: kamus-example
replicas: 1
spec:
template:
metadata:
labels:
Expand All @@ -14,20 +14,21 @@ metadata:
automountServiceAccountToken: true
initContainers:
- name: "kamus-init"
image: "<>"
image: "local/kamus:init-container-1"
imagePullPolicy: IfNotPresent
env:
- name: KAMUS_URL
value: http://hamuste.team-devops.svc.cluster.local/
value: http://kamus-decryptor.default.svc.cluster.local/
volumeMounts:
- name: encrypted-secrets
mountPath: /encrypted-secrets
- name: decrypted-secrets
mountPath: /decrypted-secrets
args: ["-e","/encrypted-secrets","-d","/decrypted-secrets/{{ .Values.decryptedJsonFileName }}"]
args: ["-e","/encrypted-secrets","-d","/decrypted-secrets", "-n", "config.json"]
containers:
- name: app
image: {{ .Values.image.repository }}/{{ default .Values.nameOverride .Values.image.name }}:{{ .Values.image.version }}
imagePullPolicy: {{ .Values.image.pullPolicy }}
image: local/kamus:example
imagePullPolicy: IfNotPresent
volumeMounts:
- name: decrypted-secrets
mountPath: /secrets
Expand Down
25 changes: 25 additions & 0 deletions example/deployment-secret/deployment.yaml
@@ -0,0 +1,25 @@
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: kamus-example
labels:
app: kamus-example
spec:
template:
metadata:
labels:
app: kamus-example
spec:
serviceAccountName: kamus-example-sa
automountServiceAccountToken: true
containers:
- name: app
image: local/kamus:example
imagePullPolicy: IfNotPresent
volumeMounts:
- name: secret-volume
mountPath: /secrets
volumes:
- name: secret-volume
secret:
secretName: kamus-example-secret
7 changes: 7 additions & 0 deletions example/deployment-secret/secret.yaml
@@ -0,0 +1,7 @@
apiVersion: v1
kind: Secret
metadata:
name: kamus-example-secret
type: Opaque
data:
config.json: ewogICAgImtleSI6ICJ0ZXN0Igp9