keyscope 1.4.2

Keyscope is a key and secret workflow
Documentation

:key: Keyscope

Keyscope is a key and secret workflow (validation, invalidation, etc.) tool built in Rust, powered by service_policy_kit.

Current workflows supported:

  • Validation

🦀 Why Rust?

  • With Rust, "If it compiles, it works." and also, it compiles to many platforms.
  • Rust is fast, has no VM, or unnecessary cruft (typically 5-8mb binaries with LOTS of code and libraries).
  • Multi purpose, safe, and generalistic - makes for healthy and expressive mission critical code. Adding code or abstraction doesn't increase bloat, doesn't hurt performance, doesn't increase chance for bugs in a radical way (less edge cases).
  • Amazing package manager: Cargo. Productive installing and running of tasks and examples.
  • Rust is getting headlines in the security community as the go-to language for security tools. Equally interesting is offensive security + Rust here and here.

:rocket: Quick Start

Grab a release from releases, or install via Homebrew:

brew tap spectralops/tap && brew install keyscope

Using keyscope

You can try out validating a key for a provider, say, Github (assuming the key is in the GITHUB_TOKEN environment variable):

$ keyscope validate github $GITHUB_TOKEN

You can see which other providers are supported by running:

$ keyscope validate --list

  .
  :
  .

twilio:validation
keyscope validate twilio -p twilio_1 -p twilio_2

twitter:validation
keyscope validate twitter -p twitter_1

zendesk:validation
keyscope validate zendesk -p zendesk_1 -p zendesk_2

Total 44 providers available.
$

And what parameters are required for a certain provider by running (say, stripe):

$ keyscope requirements stripe

provider stripe requires:
 - param: p1
   desc: stripe key
$

Finally the general structure of the validate command is:

$ keyscope validate PROVIDER -p PARAM1 -p PARAM2 .. -p PARAM_N

:white_check_mark: Validation: key should be active

You can validate a specific provider like so:

$ keyscope validate twilio -p $TWILIO_KEY

With the general pattern of:

$ keyscope validate PROVIDER -p PARAM1 -p PARAM2 ...

The number of keys/params would change based on authentication type:

  • Bearer - usually just a single key (token)
  • Basic Auth - usually 2 keys: user, password
  • OAuth - usually 2 keys: client_id, client_secret
  • And others.

Each provider in Keyscope will tell you what it requires using requirements:

$ keyscope requirements twilio

You'll get a report:

$ keyscope --verbose validate stripe -p $STRIPE_KEY

✔ stripe:validation: ok 766ms

Ran 1 interactions with 1 checks in 766ms

Success: 1
Failure: 0
  Error: 0
Skipped: 0

And an executable exit code that reflects success/failure.

You can use the --verbose flag to see API responses:

$ keyscope --verbose validate stripe -p $STRIPE_KEY

✗ stripe:validation: failed 413ms
      status_code: 200 != 401 Unauthorized

Ran 1 interactions with 1 checks in 413ms

Success: 0
Failure: 1
  Error: 0
Skipped: 0

In this case the exit code is 1 (failure).

:x: Validation: key should be inactive

When you are validating keys that are supposed to be inactive, you can use the flip flag. In this mode, a failed API access is a good thing, and the exit code will reflect that.

$ keyscope --flip validate stripe -p $STRIPE_KEY

✔ stripe:validation: ok 766ms

Ran 1 interactions with 1 checks in 766ms

In this case, the key is active - which is bad for us. Using --flip, the exit code will be 1 (failure).

:runner: Setting up a validation job

Audit active keys

You can set up a CI job (or other form of scheduled job you like) to perform an audit, by reading all parameters from a dedicated CSV file like so:

$ keyscope validate --csv-in report.csv

The format of the CSV that you need to prepare should include a header line and look like this:

provider,key1,key2,key3
twilio,tw-key1,,,

You can specify as many key columns as you like, as long as you provide an empty value for providers which don't have that many keys, and all rows contain the same amount of cells.

Audit inactive keys

If you have a dump of keys from your vault that are stale have expiry and should have been rotated, you want to test that they are all stale:

$ keyscope --flip validate --csv-in my-key-audit.csv

:link: Supported providers

We're always adding new providers, keep a link to this list or watch this repo to get updated.

We use our service_policy_kit library to specify interactions with services and their policies, if you find a service not in this list feel free to open an issue or contribute back.

testerTester: valid key

validation

tester_1 - hookbin ID (https://hookb.in)tester_2 - fake key to put as a query param

keyscope validate tester -p TESTER_1 -p TESTER_2

infurainfura API key

validation

infura_1 - infura API key

keyscope validate infura -p INFURA_1

covalenthqCovalent: valid key

validation

covalenthq_1 - covalent token

keyscope validate covalenthq -p COVALENTHQ_1

asanaAsana: valid token

validation

asana_1 - asana token

keyscope validate asana -p ASANA_1

bitlyBit.ly: valid access token

validation

bitly_1 - bit.ly token

keyscope validate bitly -p BITLY_1

ipstackipstack access key

validation

ipstack_1 - ipstack access key

keyscope validate ipstack -p IPSTACK_1

localyticsLocalytics: valid API credentials

validation

localytics_1 - localytics userlocalytics_2 - localytics key

keyscope validate localytics -p LOCALYTICS_1 -p LOCALYTICS_2

algoliaAlgolia: valid API credentials

validation

algolia_1 - algolia application IDalgolia_2 - algolia indexalgolia_3 - algolia API key

keyscope validate algolia -p ALGOLIA_1 -p ALGOLIA_2 -p ALGOLIA_3

branchiobranch.io: valid API credentials

validation

branchio_1 - branch.io keybranchio_2 - branch.io secret

keyscope validate branchio -p BRANCHIO_1 -p BRANCHIO_2

browserstackbrowserstack: valid API credentials

validation

browserstack_1 - browserstack keybrowserstack_2 - browserstack secret

keyscope validate browserstack -p BROWSERSTACK_1 -p BROWSERSTACK_2

buildkiteBuildkite: valid token

validation

buildkite_1 - buildkite token

keyscope validate buildkite -p BUILDKITE_1

datadogdatadog: valid API credentials

validation

datadog_1 - datadog API key

keyscope validate datadog -p DATADOG_1

githubgithub: valid API credentials

validation

github_1 - github token

keyscope validate github -p GITHUB_1

github-entGithub Enterprise: valid API token

validation

github-ent_1 - github enterprise instance (without http)github-ent_2 - github token

keyscope validate github-ent -p GITHUB-ENT_1 -p GITHUB-ENT_2

dropboxdropbox: valid API credentials

validation

dropbox_1 - dropbox token

keyscope validate dropbox -p DROPBOX_1

gitlabgitlab: valid API credentials

validation

gitlab_1 - gitlab token

keyscope validate gitlab -p GITLAB_1

herokuheroku: valid API credentials

validation

heroku_1 - heroku token

keyscope validate heroku -p HEROKU_1

mailchimpmailchimp: valid API credentials

validation

mailchimp_1 - mailchimp datacenter IDmailchimp_2 - mailchimp key

keyscope validate mailchimp -p MAILCHIMP_1 -p MAILCHIMP_2

mailgunmailgun: valid API credentials

validation

mailgun_1 - mailgun key

keyscope validate mailgun -p MAILGUN_1

pagerdutypagerduty: valid API credentials

validation

pagerduty_1 - pagerduty token

keyscope validate pagerduty -p PAGERDUTY_1

circlecicircleci: valid API credentials

validation

circleci_1 - circleci key

keyscope validate circleci -p CIRCLECI_1

facebook-access-tokenfacebook: valid API token

validation

facebook-access-token_1 - facebook token

keyscope validate facebook-access-token -p FACEBOOK-ACCESS-TOKEN_1

salesforcesalesforce: valid API credentials

validation

salesforce_1 - salesforce instance namesalesforce_2 - salesforce token

keyscope validate salesforce -p SALESFORCE_1 -p SALESFORCE_2

jumpcloudjumpcloud: valid API credentials

validation

jumpcloud_1 - jumpcloud key

keyscope validate jumpcloud -p JUMPCLOUD_1

saucelabs-ussaucelabs-us: valid API credentials

validation

saucelabs-us_1 - saucelabs usersaucelabs-us_2 - saucelabs key

keyscope validate saucelabs-us -p SAUCELABS-US_1 -p SAUCELABS-US_2

saucelabs-eusaucelabs-eu: valid API credentials

validation

saucelabs-eu_1 - saucelabs usersaucelabs-eu_2 - saucelabs key

keyscope validate saucelabs-eu -p SAUCELABS-EU_1 -p SAUCELABS-EU_2

sendgridsendgrid: valid API credentials

validation

sendgrid_1 - sendgrid key

keyscope validate sendgrid -p SENDGRID_1

slackslack: valid API credentials

validation

slack_1 - slack key

keyscope validate slack -p SLACK_1

slack-webhookslack-webook: valid API credentials

validation

slack-webhook_1 - slack webhook

keyscope validate slack-webhook -p SLACK-WEBHOOK_1

stripestripe: valid API credentials

validation

stripe_1 - stripe key

keyscope validate stripe -p STRIPE_1

traviscitravisci: valid API credentials

validation

travisci_1 - travisci domain, choose 'org' or 'com'travisci_2 - travisci key

keyscope validate travisci -p TRAVISCI_1 -p TRAVISCI_2

twiliotwilio: valid API credentials

validation

twilio_1 - twilio account sidtwilio_2 - twilio token

keyscope validate twilio -p TWILIO_1 -p TWILIO_2

twittertwitter: valid API credentials

validation

twitter_1 - twitter API token

keyscope validate twitter -p TWITTER_1

zendeskzendesk: valid API credentials

validation

zendesk_1 - zendesk domainzendesk_2 - zendesk key

keyscope validate zendesk -p ZENDESK_1 -p ZENDESK_2

firebasefirebase: valid API credentials

validation

firebase_1 - firebase API keyfirebase_2 - firebase ID token

keyscope validate firebase -p FIREBASE_1 -p FIREBASE_2

awsaws: valid API credentials

validation

aws_1 - AWS IDaws_2 - AWS secret

keyscope validate aws -p AWS_1 -p AWS_2

elastic-apm-secretElastic APM: secret key validation

validation

elastic-apm-secret_1 - Elastic APM host address and port, including 'http/s' partelastic-apm-secret_2 - Elastic APM secret

keyscope validate elastic-apm-secret -p ELASTIC-APM-SECRET_1 -p ELASTIC-APM-SECRET_2

artifactoryArtifactory: token validation

validation

artifactory_1 - Artifactory host (including http(s) part)artifactory_2 - Artifactory token

keyscope validate artifactory -p ARTIFACTORY_1 -p ARTIFACTORY_2

ibm-cosIBM: cloud object storage key validation (HMAC)

validation

ibm-cos_1 - IBM HMAC IDibm-cos_2 - IBM HMAC secret

keyscope validate ibm-cos -p IBM-COS_1 -p IBM-COS_2

ibm-iamIBM: cloud key validation (IAM)

validation

ibm-iam_1 - IBM cloud key

keyscope validate ibm-iam -p IBM-IAM_1

ibm-cloudantIBM: cloudant key validation (legacy)

validation

ibm-cloudant_1 - IBM cloudant hostnameibm-cloudant_2 - IBM cloudant useribm-cloudant_3 - IBM cloudant key

keyscope validate ibm-cloudant -p IBM-CLOUDANT_1 -p IBM-CLOUDANT_2 -p IBM-CLOUDANT_3

softlayerSoftlayer: validate credentials

validation

softlayer_1 - Softlayer hostnamesoftlayer_2 - Softlayer token

keyscope validate softlayer -p SOFTLAYER_1 -p SOFTLAYER_2

squareSquare: valid token

validation

square_1 - Square token

keyscope validate square -p SQUARE_1

telegram-bottelegram-bot: valid bot token

validation

telegram-bot_1 - bot key

keyscope validate telegram-bot -p TELEGRAM-BOT_1

bingmapsBing Maps API: valid access token

validation

bingmaps_1 - Bing Maps token

keyscope validate bingmaps -p BINGMAPS_1

buttercmsButterCMS: valid bot token

validation

buttercms_1 - ButterCMS API key

keyscope validate buttercms -p BUTTERCMS_1

wakatimewakatime: valid api token

validation

wakatime_1 - WakeTime API key

keyscope validate wakatime -p WAKATIME_1

calendlycalendly: valid API credentials

validation

calendly_1 - calendly API key

keyscope validate calendly -p CALENDLY_1

shodanshodan: valid api token

validation

shodan_1 - Shodan API key

keyscope validate shodan -p SHODAN_1

opsgenieopsgenie: valid api token

validation

opsgenie_1 - opsgenie API key

keyscope validate opsgenie -p OPSGENIE_1

pendopendo: valid api token

validation

pendo_1 - pendo API key

keyscope validate pendo -p PENDO_1

hubspothubspot: valid api token

validation

hubspot_1 - hubspot API key

keyscope validate hubspot -p HUBSPOT_1

lokaliselokalise: valid api token

validation

lokalise_1 - lokalise token

keyscope validate lokalise -p LOKALISE_1

:cake: Adding your own providers

You can specify a custom definitions file (here is an example):

$ keyscope -f your-definitions.yaml validate --list

Which is suitable for adding your own internal services, key issuing policies, and infrastructure.

You can also use custom definitions to test out new providers that you'd like to contribute back to keyscope :smile:

Basics of a definition

All definitions represent an interaction. A request being made, and a policy that's being checked against it.

providers:
  hookbin:
    validation:
      #
      # the request part
      #
      request:
        params:
          - name: hookbin_1
            desc: hookbin ID (https://hookb.in)
          - name: hookbin_2
            desc: fake key to put as a query param
        id: "postbin:validation"
        desc: "Postbin: valid key"
        # variable interpolation is good for all fields
        uri: "https://hookb.in/{{hookbin_1}}?q={{hookbin_2}}"
        method: post
        # you can also use headers, body, form, basic_auth and more (see defs.yaml)

      #
      # the policy part: all values are actually regular expressions and are matched against service response
      #
      response:
        status_code: "200"
        body: ok

When in doubt, you can check keyscope's own defs.yaml for real examples of how to use this infrastructure.

Tutorial: adding Dropbox

To validate if a dropbox API key works, we first need to learn about the canonical way to authenticate against that API.

First stop, API docs:

Next stop, we want to find an API call that is a representative for:

  • Has to be authenticated
  • Has to indicate that when accessed successfully with our candidate key, the key has some authoritative value. Which means, that if exposed, contains significant risk.

For this example, getting our current account sounds like something that only when we identify who we are - we're able to do.

We'll select get_current_account.

Let's start forming our interaction. First the needed skeleton: containing the name of the provider (dropbox), its ID and description below, as well as parameters required and their name and description:

dropbox:
  validation:
    request:
      id: "dropbox:validation"
      desc: "dropbox: valid API credentials"
      params:
        - name: dropbox_1
          desc: dropbox token

We keep the name of the parameter with a special convention that helps when feeding keyscope automatically:

PROVIDER_N
Where 'N' starts in 1 e.g.:
dropbox_1
dropbox_2
aws_1
...

Then, details about actually making an HTTP call, as required by Dropbox (Bearer token authentication).

uri: https://api.dropboxapi.com/2/users/get_current_account
method: post
headers:
  Authorization:
    - Bearer {{dropbox_1}}

Note that per standard, all HTTP header fields are actually arrays. It's OK to always make an array of size one if you only have one value (most common case).

We also see variable interpolation here. Where {{dropbox_1}} will get replaced by keyscope in time before making the actual call.

Finally, we want to make sure we answer the question:

  • What does it mean to have a successful call?

In our case, the Dropbox API call returns HTTP OK on success, which means a 200 status code.

And the final, complete result is this:

dropbox:
  validation:
    request:
      id: "dropbox:validation"
      desc: "dropbox: valid API credentials"
      params:
        - name: dropbox_1
          desc: dropbox token
      uri: https://api.dropboxapi.com/2/users/get_current_account
      method: post
      headers:
        Authorization:
          - Bearer {{dropbox_1}}
    response:
      status_code: "200"

Meanwhile, you can drop this provider in your own providers.yaml file and run keyscope:

$ keyscope -f providers.yaml validate dropbox -p MY_KEY

Now you can keep this in your private providers.yaml file or contribute it back to keyscope if you think other people might enjoy using it - we're happy to accept pull requests.

Thanks

To all Contributors - you make this happen, thanks!

Copyright

Copyright (c) 2021 @jondot. See LICENSE for further details.