Keys


Many cloud services require keys of one sort or another to authenticate and authorize access. Some of these use standardized authorization systems like OAuth and others use custom developer key schemes. Managing and using keys inside rulesets is a critical feature in KRL.

One of the primary reasons for having explicit support for keys in KRL is to promote code sharing. When you share a ruleset with others, you’d rather not have your keys—vital secrets—exposed. Redacting them each time you share the ruleset is a hassle. By explicitly supporting keys in the language, KRL can automatically redact keys.

Using Keys

Keys are declared in the meta section of the ruleset using the key pragma like so:

key errorstack "dakdladaoadoajdoa" 

This creates a key called errorstack with the value shown. Many times, there is more than one key that a service needs. You can also supply a map of name-value pairs for the key values:

key twitter {
  "consumer_key" : "skfjldfajsdkfaj", 
  "consumer_secret" : "fjfoiasjf;asdfjdoifjsdopfasdjfoa"
} 

This creates a key named twitter that has the value shown in the map.

Some libraries (like the twitter library) require keys that have specific names and values. When you aren’t working with a library that has specific requirements, you will likely need to access the keys to send them to the cloud service you’re working with. You can access keys stored in the meta section from within KRL expressions using the following syntax:

keys:<keyname>(<name>)

The <keyname> is the name given after the keyword key in the meta section. The <name> is optional. If it’s missing the entire value is returned. If it’s present, just the value associated with <name> in the map is returned (assuming the value is a map).

The following KRL declaration would bind the entire map associated with the twitter key to the variable my_key:

pre{
  my_key = keys:twitter();
}

On the other hand, the following KRL declaration would only bind the value associated with the name consumer_secret to the variable my_key:

pre{
  my_key = keys:twitter("consumer_secret");
}

Key Modules

KRL provides a mechanism for accessing keys that are stored in modules. A key module uses the pragma provide keys (or provides keys) to specify which previously defined keys should be made available to which rulesets. For example, is rulesets a16x175 and b16x77 require the use of a set of Dropbox keys, the following module could provide those keys specifically to the named rulesets:

ruleset b16x5 {
  meta {
    name "Dropbox keys"
    description <<
These are the keys for testing. This file should not be on a publicly available URL
    >>
    key dropbox {
       "app_key" : "<app key here>",
       "app_secret" : "<app secret here>"
    }      
    
    provide keys dropbox to a16x175, b16x77
  }
}

The rulesets using the keys would load this module as usual and use the keys it provides as usual:

ruleset a16x175 {
  meta {
    name "Dropbox module test"
    use module b16x5 
    use module b16x0 alias dropbox with
         app_key = keys:dropbox("app_key") and	   
         app_secret = keys:dropbox("app_secret")
  }

This example loads the keys in module b16x5 and then uses them to configure module b16x0.  

There is a single namespace for keys. If you put keys into multiple key modules and load them, they will all be available. The behavior of the system when there are name clashes (multiple key statements with the same name) is indeterminate.

Security Considerations

KRE tries to ensure that key values are not disclosed outside of your program. Therefore, you should be careful binding key values to variables since those values may be exposed in logging statements or any generated JavaScript. 

When using key modules as shown above, any key rulesets available on a URL should be protected so that they are not publicly viewable. For example, the ruleset could be on a WebDAV server with an appropriately formatted BASIC AUTH URL or in a private repository. 

If you're hosting on AWS S3, be sure to check the permissions of the file so that it is not writable or readable by anyone other than authorized users. You will need to create a pre-signed AWS URL. There are ways of doing this with various programming languages. I've found this project for signing AWS URLs with a Bash script to be quite useful. 



Copyright Picolabs | Licensed under Creative Commons.