dhall-secret 0.5.50 → 0.5.52
raw patch · 11 files changed
+369/−3 lines, 11 files
Files
- README.md +188/−0
- dhall-secret.cabal +7/−3
- src/Type.dhall +13/−0
- test/example.dhall +22/−0
- test/example01.dhall +23/−0
- test/example01.expected.dhall +39/−0
- test/example02.dhall +14/−0
- test/example02.encrypted.dhall +27/−0
- test/example02.expected.dhall +30/−0
- test/example02.test.key +3/−0
- test/example02.test2.key +3/−0
+ README.md view
@@ -0,0 +1,188 @@+# dhall-secret+[](https://github.com/jcouyang/dhall-secret/actions/workflows/build.yml)++A simple tool to manage secrets in Dhall configuration, inspired by [sops](https://github.com/mozilla/sops)++## Install+### nix+```+nix-env -f https://github.com/jcouyang/dhall-secret/archive/master.tar.gz -iA dhall-secret.components.exes.dhall-secret+```++### binary+Download binary according to your OS from [releases channel](https://github.com/jcouyang/dhall-secret/releases)++### docker+docker images are avail [here](https://github.com/jcouyang/dhall-secret/pkgs/container/dhall-secret)+```+docker run ghcr.io/jcouyang/dhall-secret:latest+```++## Usage++```+Usage: dhall-secret (encrypt | decrypt | gen-types) [-v|--version]++Available options:+-h,--help Show this help text+-v,--version print version++Available commands:+encrypt Encrypt a Dhall expression+decrypt Decrypt a Dhall expression+gen-types generate types+```++## Example+create a unencrypted version of Dhall file `./test/example.dhall`, put the plain text secret in `PlainText`+```dhall+let empty =+ https://prelude.dhall-lang.org/Map/empty++in { kmsExample =+ dhall-secret.AwsKmsDecrypted+ { KeyId = "alias/dhall-secret/test"+ , PlainText = "a-secret"+ , EncryptionContext = empty Text Text+ }+ , ageSecret =+ dhall-secret.AgeDecrypted+ { Recipients =+ [ "age1rl8j26etwulmav6yn8p4huu6944n7hsr2pyu2dr0evjzsj2tq92q48arjp"+ , "age1xmcwr5gpzkaxdwz2udww7lht2j4evp4vpl0ujeu64pe5ncpsk9zqhkfw5y"+ ]+ , PlainText = "another-secret"+ }+ , somethingElse = "not-secret"+ }++```++The file contains two secrets to be encrypted+- `a-secret` is `dhall-secret.AwsKmsDecrypted` needs to be encrypted via KMS with key id `alias/dhall-secret/test`+- `another-secret` is a `dhall-secret.AgeDecrypted` needs to be encrypted via Age, only who from `Recipients` can decrypt the message.+- `not-a-secret` won't be encrypted++### AWS KMS++1. login to your AWS account, either through `~/.aws/credentials` or `AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY` environment++2. probably need to also `export AWS_REGION=<your-kms-key-region>`++### Age++You will need to export AGE-SECRET-KEY to `DHALL_SECRET_AGE_KEYS` env to decrypt a dhall+```+export DHALL_SECRET_AGE_KEYS=AGE-SECRET-KEY-1GLAZ75TDSSR647WXD0MH3RUU8XGRK6R5SD8UGQ6C6R9MCYR03ULQSUC7D6+dhall-secret decrypt -f ./test/example02.encrypted.dhall+```++or export multiple keys in multiple lines+```+export DHALL_SECRET_AGE_KEYS="AGE-SECRET-KEY-1HKC2ZRPFFY66049G5EWYLT2PMYKTPN6UW6RFEEEN3JEEWTFFFDNQ2QTC8M+AGE-SECRET-KEY-1GLAZ75TDSSR647WXD0MH3RUU8XGRK6R5SD8UGQ6C6R9MCYR03ULQSUC7D6"+dhall-secret decrypt -f ./test/example02.encrypted.dhall+```++you don't need to have the secret key to encrypt the file.++### Encrypt+#### from stdin to stdout+```+> dhall-secret encrypt+dhall-secret.AgeDecrypted+ { Recipients =+ [ "age1rl8j26etwulmav6yn8p4huu6944n7hsr2pyu2dr0evjzsj2tq92q48arjp" ]+ , PlainText = "hello age!"+ }+[Ctrl-D]+let dhall-secret =+ https://raw.githubusercontent.com/jcouyang/dhall-secret/master/Type.dhall+ sha256:d7b55a2f433e19cf623d58c339346a604d96989f60cffdecee125a504a068dc9++in dhall-secret.AgeEncrypted+ { Recipients =+ [ "age1rl8j26etwulmav6yn8p4huu6944n7hsr2pyu2dr0evjzsj2tq92q48arjp" ]+ , CiphertextBlob =+ ''+ -----BEGIN AGE ENCRYPTED FILE-----+ YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBEUHJPRnJzV2JVL2VKTDE3+ VFpOVFZqOHhIMlhsNCtrNjQ4ZU95cjQ1T25rCk42cFBjcVRUV3ZZYkd0dUxBakN6+ YVNzY1k5WEtNRUJNbjI5YUs3RThlQWcKLS0tIHNObWFIZW9MR2FsekQwY0dyZ3hF+ VmdVYzVGRDRDUWFzWTN3N3RGRWVCbG8KSwwDZ5d+O1w0U8AQB4TRdbA7V20dk2kk+ 5P1QNjxYMEyHyJKiijRyltq++ -----END AGE ENCRYPTED FILE-----+ ''+ }+```++#### encrypt file in place+```+dhall-secret encrypt -f test/example.dhall --inplace+```+#### to a new file+```+dhall-secret encrypt -f test/example.dhall -o test/example.encrypted.dhall+```+#### update a encrypted file+you can update a encrypted file with dhall expr without needing to decrypt the file+```+dhall-secret encrypt <<< './test/example02.dhall with plain = dhall.AgeDecrypted {PlainText = "not plain any more", Recipients = ["age1xmcwr5gpzkaxdwz2udww7lht2j4evp4vpl0ujeu64pe5ncpsk9zqhkfw5y"]}'+```++### Decrypt+#### to stdout+```+> dhall-secret decrypt -f test/example.encrypted.dhall+let dhall-secret = ...+in { aesExample =+ dhall-secret.Aes256Decrypted+ { KeyEnvName = "MY_AES_SECRET"+ , PlainText = "another secret to be encrypted"+ }+ , kmsExample =+ dhall-secret.AwsKmsDecrypted+ { KeyId =+ "arn:aws:kms:ap-southeast-2:930712508576:key/5d2e1d54-c2e6-49a8-924d-bed828e792ed"+ , PlainText = "a secret to be encrypted"+ , EncryptionContext = [] : List { mapKey : Text, mapValue : Text }+ }+ , somethingElse = "not secret"+ }+```+#### in place+```+dhall-secret decrypt -f test/example.encrypted.dhall --inplace+```+#### to a new file+```+dhall-secret decrypt -f test/example.encrypted.dhall -o test/example.dhall+```+#### plaintext+`--plain-text` will output dhall without types+```+> dhall-secret decrypt -f ./test/example02.encrypted.dhall -p+{ foo =+ { ageSecret =+ dhall-secret.AgeDecrypted+ { Recipients =+ [ "age1rl8j26etwulmav6yn8p4huu6944n7hsr2pyu2dr0evjzsj2tq92q48arjp"+ , "age1xmcwr5gpzkaxdwz2udww7lht2j4evp4vpl0ujeu64pe5ncpsk9zqhkfw5y"+ ]+ , PlainText = "hello age!"+ }+ , plain = "hello world"+ }+}+```+it is very useful when you want to convert it to yaml/json+```+dhall-secret decrypt -f ./test/example02.encrypted.dhall -p | dhall-to-yaml+foo:+ ageSecret: "hello age!"+ plain: hello world+```+### Re-encrypt+```+dhall-secret decrypt -f test/example.encrypted.dhall | dhall-secret encrypt --in-place+```
dhall-secret.cabal view
@@ -20,7 +20,7 @@ -- PVP summary: +-+------- breaking API changes -- | | +----- non-breaking API additions -- | | | +--- code changes with no API change-version: 0.5.50+version: 0.5.52 -- A short (one-line) description of the package. synopsis: Encrypt Decrypt Dhall expressions@@ -31,7 +31,7 @@ homepage: https://github.com/jcouyang/dhall-secret -- The license under which the package is released.-license: Apache-2.0+license: BSD-3-Clause -- The file containing the license text. license-file: LICENSE@@ -48,7 +48,11 @@ build-type: Simple -- Extra source files to be distributed with the package, such as examples, or a tutorial module.--- extra-source-files:+extra-source-files:+ README.md+ src/Type.dhall+ test/*.key+ test/*.dhall source-repository head type: git location: https://github.com/jcouyang/dhall-secret
+ src/Type.dhall view
@@ -0,0 +1,13 @@+< AgeDecrypted : { PlainText : Text, Recipients : List Text }+| AgeEncrypted : { CiphertextBlob : Text, Recipients : List Text }+| AwsKmsDecrypted :+ { EncryptionContext : List { mapKey : Text, mapValue : Text }+ , KeyId : Text+ , PlainText : Text+ }+| AwsKmsEncrypted :+ { CiphertextBlob : Text+ , EncryptionContext : List { mapKey : Text, mapValue : Text }+ , KeyId : Text+ }+>
+ test/example.dhall view
@@ -0,0 +1,22 @@+let dhall-secret =+ https://raw.githubusercontent.com/jcouyang/dhall-secret/38fc27c7da185dda1ddae67c389080154c2336fc/Type.dhall++let empty =+ https://raw.githubusercontent.com/dhall-lang/dhall-lang/v22.0.0/Prelude/Map/empty.dhall++in { kmsExample =+ dhall-secret.AwsKmsDecrypted+ { KeyId = "alias/dhall-secret/test"+ , PlainText = "a secret to be encrypted"+ , EncryptionContext = empty Text Text+ }+ , ageSecret =+ dhall-secret.AgeDecrypted+ { Recipients =+ [ "age1rl8j26etwulmav6yn8p4huu6944n7hsr2pyu2dr0evjzsj2tq92q48arjp"+ , "age1xmcwr5gpzkaxdwz2udww7lht2j4evp4vpl0ujeu64pe5ncpsk9zqhkfw5y"+ ]+ , PlainText = "hello age!"+ }+ , somethingElse = "not secret"+ }
+ test/example01.dhall view
@@ -0,0 +1,23 @@+let T = ./Type.dhall++let empty =+ https://raw.githubusercontent.com/dhall-lang/dhall-lang/v22.0.0/Prelude/Map/empty.dhall++in { foo =+ { aws =+ { noContext =+ T.AwsKmsDecrypted+ { KeyId = "alias/dhall-secret/test"+ , PlainText = "hello kms"+ , EncryptionContext = empty Text Text+ }+ , withContext =+ T.AwsKmsDecrypted+ { KeyId = "alias/dhall-secret/test"+ , PlainText = "hello kms with context"+ , EncryptionContext = toMap { crew = "bar", environment = "prod" }+ }+ }+ , plain = "hello world"+ }+ }
+ test/example01.expected.dhall view
@@ -0,0 +1,39 @@+let dhall-secret =+ < Aes256Decrypted : { KeyEnvName : Text, PlainText : Text }+ | Aes256Encrypted :+ { CiphertextBlob : Text, IV : Text, KeyEnvName : Text }+ | AwsKmsDecrypted :+ { EncryptionContext : List { mapKey : Text, mapValue : Text }+ , KeyId : Text+ , PlainText : Text+ }+ | AwsKmsEncrypted :+ { CiphertextBlob : Text+ , EncryptionContext : List { mapKey : Text, mapValue : Text }+ , KeyId : Text+ }+ >++in { foo =+ { aws =+ { noContext =+ dhall-secret.AwsKmsDecrypted+ { KeyId =+ "arn:aws:kms:ap-southeast-2:930712508576:key/5d2e1d54-c2e6-49a8-924d-bed828e792ed"+ , PlainText = "hello kms"+ , EncryptionContext = [] : List { mapKey : Text, mapValue : Text }+ }+ , withContext =+ dhall-secret.AwsKmsDecrypted+ { KeyId =+ "arn:aws:kms:ap-southeast-2:930712508576:key/5d2e1d54-c2e6-49a8-924d-bed828e792ed"+ , PlainText = "hello kms with context"+ , EncryptionContext =+ [ { mapKey = "crew", mapValue = "bar" }+ , { mapKey = "environment", mapValue = "prod" }+ ]+ }+ }+ , plain = "hello world"+ }+ }
+ test/example02.dhall view
@@ -0,0 +1,14 @@+let T = https://oyanglul.us/dhall-secret/Type.dhall++in { foo =+ { ageSecret =+ T.AgeDecrypted+ { Recipients =+ [ "age1rl8j26etwulmav6yn8p4huu6944n7hsr2pyu2dr0evjzsj2tq92q48arjp"+ , "age1xmcwr5gpzkaxdwz2udww7lht2j4evp4vpl0ujeu64pe5ncpsk9zqhkfw5y"+ ]+ , PlainText = "hello age!"+ }+ , plain = "hello world"+ }+ }
+ test/example02.encrypted.dhall view
@@ -0,0 +1,27 @@+let dhall-secret =+ https://raw.githubusercontent.com/jcouyang/dhall-secret/master/Type.dhall+ sha256:d7b55a2f433e19cf623d58c339346a604d96989f60cffdecee125a504a068dc9++in { foo =+ { ageSecret =+ dhall-secret.AgeEncrypted+ { Recipients =+ [ "age1rl8j26etwulmav6yn8p4huu6944n7hsr2pyu2dr0evjzsj2tq92q48arjp"+ , "age1xmcwr5gpzkaxdwz2udww7lht2j4evp4vpl0ujeu64pe5ncpsk9zqhkfw5y"+ ]+ , CiphertextBlob =+ ''+ -----BEGIN AGE ENCRYPTED FILE-----+ YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBINUtOMnJzMFdyZXhnSUEr+ UGcyUlBuQ1pqdDRvTUtEYUVnS0FGR25HOWpJClFKVlNEeTBkZGJFUjAyNHJJMlRs+ M1VjN1FBclc4Qmh0M2kvRE9lV0JoZWcKLT4gWDI1NTE5IEc0ejJxclZFRmI2cWww+ Q0Ztc3VoK2FyYVNweXJWUURoWHVxN0ZNSHZ3UUEKUVUyT3NsRFN4MG4zaENITVNv+ OFhwaHk0cnRLK0RlaldYR25DYXpSZkVzcwotLS0gVlpPVGNHRnlZbU5mTWJHZ0Uz+ RmFTZmt0K0JZN3ZiNU0yRTNoVlpFOG03awrR//vOiCopVyEUXXrhiWDepXO4Ji8L+ E4nBuypVhk/xOWSTnNP0isKElAg=+ -----END AGE ENCRYPTED FILE-----+ ''+ }+ , plain = "hello world"+ }+ }
+ test/example02.expected.dhall view
@@ -0,0 +1,30 @@+let dhall-secret =+ < Aes256Decrypted :+ { Context : Text, KeyEnvName : Text, PlainText : Text }+ | Aes256Encrypted :+ { CiphertextBlob : Text+ , Context : Text+ , KeyEnvName : Text+ , Nonce : Text+ , Salt : Text+ , Tag : Text+ }+ | AwsKmsDecrypted :+ { EncryptionContext : List { mapKey : Text, mapValue : Text }+ , KeyId : Text+ , PlainText : Text+ }+ | AwsKmsEncrypted :+ { CiphertextBlob : Text+ , EncryptionContext : List { mapKey : Text, mapValue : Text }+ , KeyId : Text+ }+ >++in { foo =+ { aes256 =+ dhall-secret.Aes256Decrypted+ { KeyEnvName = "MY_AES_SECRET", PlainText = "hello AES" }+ , plain = "hello world"+ }+ }
+ test/example02.test.key view
@@ -0,0 +1,3 @@+# created: 2022-10-17T18:48:15+11:00+# public key: age1rl8j26etwulmav6yn8p4huu6944n7hsr2pyu2dr0evjzsj2tq92q48arjp+AGE-SECRET-KEY-1GLAZ75TDSSR647WXD0MH3RUU8XGRK6R5SD8UGQ6C6R9MCYR03ULQSUC7D6
+ test/example02.test2.key view
@@ -0,0 +1,3 @@+# created: 2022-10-17T18:48:55+11:00+# public key: age1xmcwr5gpzkaxdwz2udww7lht2j4evp4vpl0ujeu64pe5ncpsk9zqhkfw5y+AGE-SECRET-KEY-1HKC2ZRPFFY66049G5EWYLT2PMYKTPN6UW6RFEEEN3JEEWTFFFDNQ2QTC8M