diff options
author | Kamil Trzciński <ayufan@ayufan.eu> | 2018-11-28 13:15:23 +0100 |
---|---|---|
committer | Kamil Trzciński <ayufan@ayufan.eu> | 2018-11-28 13:29:01 +0100 |
commit | 06a45b94c7d24ac27a9341cb7e697a48b676df59 (patch) | |
tree | acc0e5020d5c9061fad492778de1ab0f25096694 | |
parent | 1cd570cf77b79f37f30ef3ccd399c337056aa236 (diff) | |
download | gitlab-ce-secrets-handling.tar.gz |
Add security guidelinesecrets-handling
-rw-r--r-- | doc/development/README.md | 4 | ||||
-rw-r--r-- | doc/development/security_storing secrets.md | 128 |
2 files changed, 132 insertions, 0 deletions
diff --git a/doc/development/README.md b/doc/development/README.md index bcf57a223f5..4b9822dd3ce 100644 --- a/doc/development/README.md +++ b/doc/development/README.md @@ -120,6 +120,10 @@ description: 'Learn how to contribute to GitLab.' - [Building a package for testing purposes](build_test_package.md) +## Security + +- [Storing secrets](security_handling_secrets.md) + ## Compliance - [Licensing](licensing.md) for ensuring license compliance diff --git a/doc/development/security_storing secrets.md b/doc/development/security_storing secrets.md new file mode 100644 index 00000000000..6764fb450da --- /dev/null +++ b/doc/development/security_storing secrets.md @@ -0,0 +1,128 @@ +# Guidelines for storing secrets + +As part of securely storing data within application this guideline +describes a methods to handle various types of passwords, +describe a entropy of data, and describe a methods for storing them +within the application. + +**This does not describe the way to store user passwords within database, +but rather dependent passwords used for authenticating with different services.** + +## Types of passwords + +We can distinguish different types of data: + +1. **user provided secrets**: are password/tokens or URLs that are passed by user via forms and API: + + 1. They can be any type of string, + 2. They have unknown entropy, + 3. They have with minimal length of 1, + 4. User provided passwords are suspectible to dictionary brute force attacks, + 5. Passwords like that can be replicated many times within the application across different users, + 6. By design they should be easily accessible, so they representation should be reversible. + +1. **machine generated secrets**: are tokens that are generated by GitLab in secure way (cryptographic secure random): + + 1. They are generated from source of big entropy (cryptographic secure random), + 2. They have big dictionary space (are longer than 19 characters), + 3. They are unique within the application, + 4. They can be stored in irreversible form: thus generated, presented to user, forgotten. + +## The **user provided secrets** + +Nature of such secrets says that we have to deal with them very carefully, +as we cannot assume anything about they structure. + +### CI Variables + +One example of user secret is `Ci::Variable`: + +1. They are stored in database, +2. They are user provided, +3. They can be any type of data (ex. `a`), +4. The same value can be used by different projects or even different variables within the same project, +5. We access them in very specific conditions. + +#### Store user provided secret + +```ruby +class Ci::Variable + attr_encrypted :value, + mode: :per_attribute_iv_and_salt, + key: Settings.attr_encrypted_db_key_base, + algorithm: 'aes-256-gcm' +end +``` + +Each secret is encrypted indivdually, by using database key (global to GitLab) +and using per-secret initialization vector (IV, local to secret). Since we assume that +`IV` is random and unique within database, for the same secret its encrypted +representation will not be equal. + +## The **machine generated secrets** + +Machine generated secrets are generated by GitLab. +GitLab allows user to see the secret, ideally at most once. +Machine generated secrets can be used to authenticate external +service against GitLab. + +We can distinguish two ways of dealing with machine generated secrets: + +1. irreversible hashing (preferred): we present secret once, and store then in hashed form, +2. encryption (discouraged): we store secret, but we have to present it to user multiple times. + +The `irreversible hashing` is preferred method as this blocks us from always know the plain text. Our user flow should be build in a way that allows user to see the secret only once, and thus allow us to save them in `irreversible form`. Example of good implementation is `Personal Access Token`. The example of bad design from security point of view is `Runner Registration Token`. + +The reversible form should be only used for dealing with legacy machine secrets, +and should not be used for any new introduced machine secrets. + +### Personal Access Token (irreversible hashing) + +Example of machine generated secret is `Personal Access Token`: + +1. They are stored in database, +1. They are presented to user only once, when created, +1. They representation is persisted in database in irreversible form (hashing), +1. They are used for authenticating external tools on behalf of the user, +1. They entropy is know, +1. We assume that the secret is unique across GitLab, +1. We can cheaply perform database-wide search of hashed secret for the purpose of authentication, + +#### Store hashed machine generated secret + +```ruby +class PersonalAccessToken + add_authentication_token_field :token, digest: true +end +``` + +Each secret is stored in irreversible form (hashing of SHA256). +The secret is concatinated with database key (global to GitLab). +Since we assume that database key and secret have do have high entropy, +it is impossible to perform brute force attack. + +### Runner Registration Token (encrypted) + +Example of machine generated secret that is encrypted is `Runner Registration Token`: + +1. They are stored in database, +1. They are presented to user many times after they are created, +1. They representation is persisted in database in reversible form (encryption), +1. They are used for authenticating external tools on behalf of the user, +1. They entropy is know, +1. We assume that the secret is unique across GitLab, +1. We can cheaply perform database-wide search of hashed secret for the purpose of authentication, + +#### Store encrypted machine generated secret + +```ruby +class Project + add_authentication_token_field :runner_registration_token, encrypted: true +end +``` + +Each secret is stored in reversible form (AES256/GCM encryption). +The secret is concatinated with database key (global to GitLab). +Since we assume that database key and secret have do have high entropy, +it is impossible to perform brute force attack on such secret. +However, by knowing database key it is possible to reverse to plain text form. |