summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKamil Trzciński <ayufan@ayufan.eu>2018-11-28 13:15:23 +0100
committerKamil Trzciński <ayufan@ayufan.eu>2018-11-28 13:29:01 +0100
commit06a45b94c7d24ac27a9341cb7e697a48b676df59 (patch)
treeacc0e5020d5c9061fad492778de1ab0f25096694
parent1cd570cf77b79f37f30ef3ccd399c337056aa236 (diff)
downloadgitlab-ce-secrets-handling.tar.gz
Add security guidelinesecrets-handling
-rw-r--r--doc/development/README.md4
-rw-r--r--doc/development/security_storing secrets.md128
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.