portunus 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +3 -0
  3. data/.nvmrc +1 -0
  4. data/.travis.yml +27 -0
  5. data/CODE_OF_CONDUCT.md +74 -0
  6. data/Gemfile +6 -0
  7. data/Gemfile.lock +189 -0
  8. data/LICENSE.txt +21 -0
  9. data/README.md +289 -0
  10. data/Rakefile +2 -0
  11. data/bin/console +14 -0
  12. data/bin/setup +8 -0
  13. data/lib/Rakefile +4 -0
  14. data/lib/generators/install_generator.rb +26 -0
  15. data/lib/generators/templates/create_portunus.rb.erb +28 -0
  16. data/lib/portunus/configuration.rb +49 -0
  17. data/lib/portunus/data_encryption_key.rb +25 -0
  18. data/lib/portunus/data_key_generator.rb +55 -0
  19. data/lib/portunus/encryptable.rb +42 -0
  20. data/lib/portunus/encrypters/open_ssl_aes.rb +58 -0
  21. data/lib/portunus/encrypters/time.rb +1 -0
  22. data/lib/portunus/field_configurer.rb +157 -0
  23. data/lib/portunus/hasher.rb +9 -0
  24. data/lib/portunus/master_key.rb +15 -0
  25. data/lib/portunus/railtie.rb +14 -0
  26. data/lib/portunus/rotators/dek.rb +69 -0
  27. data/lib/portunus/rotators/kek.rb +51 -0
  28. data/lib/portunus/storage_adaptors/credentials.rb +48 -0
  29. data/lib/portunus/storage_adaptors/environment.rb +67 -0
  30. data/lib/portunus/tasks/generate_keys.rake +36 -0
  31. data/lib/portunus/tasks/rotate_keys.rake +36 -0
  32. data/lib/portunus/type_caster.rb +37 -0
  33. data/lib/portunus/type_casters/boolean.rb +39 -0
  34. data/lib/portunus/type_casters/date.rb +29 -0
  35. data/lib/portunus/type_casters/date_time.rb +29 -0
  36. data/lib/portunus/type_casters/float.rb +29 -0
  37. data/lib/portunus/type_casters/integer.rb +29 -0
  38. data/lib/portunus/type_casters/string.rb +29 -0
  39. data/lib/portunus/version.rb +3 -0
  40. data/lib/portunus.rb +39 -0
  41. data/portunus.gemspec +51 -0
  42. data/tmp/log/development.log +0 -0
  43. metadata +255 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: e68d034c4896eb04c0540e5937ebe6cea88af51bd1ee0b66526d1e84eb92d6db
4
+ data.tar.gz: fb0c26ef7df5bdfdbf58feec0dbd13b222598f9f07196231fe06351d72d0f89a
5
+ SHA512:
6
+ metadata.gz: 50e8be7b50b816b1c45d6743085004be1b9e6e6b3a64ed1de57836829d46f7d8b1bb5145483cf997b4d633693a7da84b9daea67d4b2484c1a6f88f0b48718a08
7
+ data.tar.gz: e2966752917367326122e3976662cde66810cfa536c0ebb19c71caf2a65eedb88b5832f7efeb0dac635eb7f19a28823fb0eebccf95553056c139fc40637bc66a
data/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ log/*
2
+ coverage
3
+ log
data/.nvmrc ADDED
@@ -0,0 +1 @@
1
+ v13.5.0
data/.travis.yml ADDED
@@ -0,0 +1,27 @@
1
+ env:
2
+ global:
3
+ - CC_TEST_REPORTER_ID=f40f50c1b06c16f8e703b01facaf313bcd0a7aa56100b9b077648607ca050833
4
+ cache:
5
+ bundler: true
6
+ language: ruby
7
+ rvm:
8
+ - 2.5
9
+ - 2.6
10
+ - 2.7
11
+ before_install:
12
+ - nvm install # Install node version from .nvmrc
13
+ - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
14
+ - chmod +x ./cc-test-reporter
15
+ install:
16
+ - bundle install --without production --path=${BUNDLE_PATH:-vendor/bundle}
17
+ - npm install
18
+ before_script:
19
+ - bin/setup
20
+ - ./cc-test-reporter before-build
21
+ script:
22
+ - bundle exec rspec spec/
23
+ after_script:
24
+ - ./cc-test-reporter format-coverage -t simplecov -o coverage/codeclimate.backend.json coverage/backend/.resultset.json # Format backend coverage
25
+ # - ./cc-test-reporter format-coverage -t lcov -o coverage/codeclimate.frontend.json coverage/frontend/lcov.info # Format frontend coverage
26
+ - ./cc-test-reporter sum-coverage coverage/codeclimate.*.json -p 1 # Sum both coverage parts into coverage/codeclimate.json
27
+ - if [[ "$TRAVIS_TEST_RESULT" == 0 ]]; then ./cc-test-reporter upload-coverage; fi # Upload coverage/codeclimate.json
@@ -0,0 +1,74 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ In the interest of fostering an open and welcoming environment, we as
6
+ contributors and maintainers pledge to making participation in our project and
7
+ our community a harassment-free experience for everyone, regardless of age, body
8
+ size, disability, ethnicity, gender identity and expression, level of experience,
9
+ nationality, personal appearance, race, religion, or sexual identity and
10
+ orientation.
11
+
12
+ ## Our Standards
13
+
14
+ Examples of behavior that contributes to creating a positive environment
15
+ include:
16
+
17
+ * Using welcoming and inclusive language
18
+ * Being respectful of differing viewpoints and experiences
19
+ * Gracefully accepting constructive criticism
20
+ * Focusing on what is best for the community
21
+ * Showing empathy towards other community members
22
+
23
+ Examples of unacceptable behavior by participants include:
24
+
25
+ * The use of sexualized language or imagery and unwelcome sexual attention or
26
+ advances
27
+ * Trolling, insulting/derogatory comments, and personal or political attacks
28
+ * Public or private harassment
29
+ * Publishing others' private information, such as a physical or electronic
30
+ address, without explicit permission
31
+ * Other conduct which could reasonably be considered inappropriate in a
32
+ professional setting
33
+
34
+ ## Our Responsibilities
35
+
36
+ Project maintainers are responsible for clarifying the standards of acceptable
37
+ behavior and are expected to take appropriate and fair corrective action in
38
+ response to any instances of unacceptable behavior.
39
+
40
+ Project maintainers have the right and responsibility to remove, edit, or
41
+ reject comments, commits, code, wiki edits, issues, and other contributions
42
+ that are not aligned to this Code of Conduct, or to ban temporarily or
43
+ permanently any contributor for other behaviors that they deem inappropriate,
44
+ threatening, offensive, or harmful.
45
+
46
+ ## Scope
47
+
48
+ This Code of Conduct applies both within project spaces and in public spaces
49
+ when an individual is representing the project or its community. Examples of
50
+ representing a project or community include using an official project e-mail
51
+ address, posting via an official social media account, or acting as an appointed
52
+ representative at an online or offline event. Representation of a project may be
53
+ further defined and clarified by project maintainers.
54
+
55
+ ## Enforcement
56
+
57
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
+ reported by contacting the project team at colinpetruno@gmail.com. All
59
+ complaints will be reviewed and investigated and will result in a response that
60
+ is deemed necessary and appropriate to the circumstances. The project team is
61
+ obligated to maintain confidentiality with regard to the reporter of an incident.
62
+ Further details of specific enforcement policies may be posted separately.
63
+
64
+ Project maintainers who do not follow or enforce the Code of Conduct in good
65
+ faith may face temporary or permanent repercussions as determined by other
66
+ members of the project's leadership.
67
+
68
+ ## Attribution
69
+
70
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71
+ available at [http://contributor-covenant.org/version/1/4][version]
72
+
73
+ [homepage]: http://contributor-covenant.org
74
+ [version]: http://contributor-covenant.org/version/1/4/
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in portunus.gemspec
6
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,189 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ portunus (0.3.0)
5
+ aes
6
+ openssl (>= 2.1.0)
7
+ rails (>= 5.0.0)
8
+
9
+ GEM
10
+ remote: https://rubygems.org/
11
+ specs:
12
+ actioncable (6.0.2.1)
13
+ actionpack (= 6.0.2.1)
14
+ nio4r (~> 2.0)
15
+ websocket-driver (>= 0.6.1)
16
+ actionmailbox (6.0.2.1)
17
+ actionpack (= 6.0.2.1)
18
+ activejob (= 6.0.2.1)
19
+ activerecord (= 6.0.2.1)
20
+ activestorage (= 6.0.2.1)
21
+ activesupport (= 6.0.2.1)
22
+ mail (>= 2.7.1)
23
+ actionmailer (6.0.2.1)
24
+ actionpack (= 6.0.2.1)
25
+ actionview (= 6.0.2.1)
26
+ activejob (= 6.0.2.1)
27
+ mail (~> 2.5, >= 2.5.4)
28
+ rails-dom-testing (~> 2.0)
29
+ actionpack (6.0.2.1)
30
+ actionview (= 6.0.2.1)
31
+ activesupport (= 6.0.2.1)
32
+ rack (~> 2.0, >= 2.0.8)
33
+ rack-test (>= 0.6.3)
34
+ rails-dom-testing (~> 2.0)
35
+ rails-html-sanitizer (~> 1.0, >= 1.2.0)
36
+ actiontext (6.0.2.1)
37
+ actionpack (= 6.0.2.1)
38
+ activerecord (= 6.0.2.1)
39
+ activestorage (= 6.0.2.1)
40
+ activesupport (= 6.0.2.1)
41
+ nokogiri (>= 1.8.5)
42
+ actionview (6.0.2.1)
43
+ activesupport (= 6.0.2.1)
44
+ builder (~> 3.1)
45
+ erubi (~> 1.4)
46
+ rails-dom-testing (~> 2.0)
47
+ rails-html-sanitizer (~> 1.1, >= 1.2.0)
48
+ activejob (6.0.2.1)
49
+ activesupport (= 6.0.2.1)
50
+ globalid (>= 0.3.6)
51
+ activemodel (6.0.2.1)
52
+ activesupport (= 6.0.2.1)
53
+ activerecord (6.0.2.1)
54
+ activemodel (= 6.0.2.1)
55
+ activesupport (= 6.0.2.1)
56
+ activestorage (6.0.2.1)
57
+ actionpack (= 6.0.2.1)
58
+ activejob (= 6.0.2.1)
59
+ activerecord (= 6.0.2.1)
60
+ marcel (~> 0.3.1)
61
+ activesupport (6.0.2.1)
62
+ concurrent-ruby (~> 1.0, >= 1.0.2)
63
+ i18n (>= 0.7, < 2)
64
+ minitest (~> 5.1)
65
+ tzinfo (~> 1.1)
66
+ zeitwerk (~> 2.2)
67
+ aes (0.5.0)
68
+ binding_of_caller (0.8.0)
69
+ debug_inspector (>= 0.0.1)
70
+ builder (3.2.4)
71
+ codeclimate-test-reporter (1.0.7)
72
+ simplecov
73
+ coderay (1.1.2)
74
+ concurrent-ruby (1.1.6)
75
+ crass (1.0.6)
76
+ debug_inspector (0.0.3)
77
+ diff-lcs (1.3)
78
+ docile (1.3.2)
79
+ erubi (1.9.0)
80
+ globalid (0.4.2)
81
+ activesupport (>= 4.2.0)
82
+ i18n (1.8.2)
83
+ concurrent-ruby (~> 1.0)
84
+ ipaddr (1.2.2)
85
+ json (2.3.0)
86
+ loofah (2.4.0)
87
+ crass (~> 1.0.2)
88
+ nokogiri (>= 1.5.9)
89
+ mail (2.7.1)
90
+ mini_mime (>= 0.1.1)
91
+ marcel (0.3.3)
92
+ mimemagic (~> 0.3.2)
93
+ method_source (0.9.2)
94
+ mimemagic (0.3.4)
95
+ mini_mime (1.0.2)
96
+ mini_portile2 (2.4.0)
97
+ minitest (5.14.0)
98
+ nio4r (2.5.2)
99
+ nokogiri (1.10.9)
100
+ mini_portile2 (~> 2.4.0)
101
+ openssl (2.1.2)
102
+ ipaddr
103
+ pry (0.12.2)
104
+ coderay (~> 1.1.0)
105
+ method_source (~> 0.9.0)
106
+ pry-rails (0.3.9)
107
+ pry (>= 0.10.4)
108
+ pry-stack_explorer (0.4.9.3)
109
+ binding_of_caller (>= 0.7)
110
+ pry (>= 0.9.11)
111
+ rack (2.2.2)
112
+ rack-test (1.1.0)
113
+ rack (>= 1.0, < 3)
114
+ rails (6.0.2.1)
115
+ actioncable (= 6.0.2.1)
116
+ actionmailbox (= 6.0.2.1)
117
+ actionmailer (= 6.0.2.1)
118
+ actionpack (= 6.0.2.1)
119
+ actiontext (= 6.0.2.1)
120
+ actionview (= 6.0.2.1)
121
+ activejob (= 6.0.2.1)
122
+ activemodel (= 6.0.2.1)
123
+ activerecord (= 6.0.2.1)
124
+ activestorage (= 6.0.2.1)
125
+ activesupport (= 6.0.2.1)
126
+ bundler (>= 1.3.0)
127
+ railties (= 6.0.2.1)
128
+ sprockets-rails (>= 2.0.0)
129
+ rails-dom-testing (2.0.3)
130
+ activesupport (>= 4.2.0)
131
+ nokogiri (>= 1.6)
132
+ rails-html-sanitizer (1.3.0)
133
+ loofah (~> 2.3)
134
+ railties (6.0.2.1)
135
+ actionpack (= 6.0.2.1)
136
+ activesupport (= 6.0.2.1)
137
+ method_source
138
+ rake (>= 0.8.7)
139
+ thor (>= 0.20.3, < 2.0)
140
+ rake (13.0.1)
141
+ rspec (3.9.0)
142
+ rspec-core (~> 3.9.0)
143
+ rspec-expectations (~> 3.9.0)
144
+ rspec-mocks (~> 3.9.0)
145
+ rspec-core (3.9.1)
146
+ rspec-support (~> 3.9.1)
147
+ rspec-expectations (3.9.0)
148
+ diff-lcs (>= 1.2.0, < 2.0)
149
+ rspec-support (~> 3.9.0)
150
+ rspec-mocks (3.9.1)
151
+ diff-lcs (>= 1.2.0, < 2.0)
152
+ rspec-support (~> 3.9.0)
153
+ rspec-support (3.9.2)
154
+ simplecov (0.17.1)
155
+ docile (~> 1.1)
156
+ json (>= 1.8, < 3)
157
+ simplecov-html (~> 0.10.0)
158
+ simplecov-html (0.10.2)
159
+ sprockets (4.0.0)
160
+ concurrent-ruby (~> 1.0)
161
+ rack (> 1, < 3)
162
+ sprockets-rails (3.2.1)
163
+ actionpack (>= 4.0)
164
+ activesupport (>= 4.0)
165
+ sprockets (>= 3.0.0)
166
+ sqlite3 (1.4.2)
167
+ thor (1.0.1)
168
+ thread_safe (0.3.6)
169
+ tzinfo (1.2.6)
170
+ thread_safe (~> 0.1)
171
+ websocket-driver (0.7.1)
172
+ websocket-extensions (>= 0.1.0)
173
+ websocket-extensions (0.1.4)
174
+ zeitwerk (2.3.0)
175
+
176
+ PLATFORMS
177
+ ruby
178
+
179
+ DEPENDENCIES
180
+ bundler (> 1.17)
181
+ codeclimate-test-reporter
182
+ portunus!
183
+ pry-rails
184
+ pry-stack_explorer
185
+ rails (>= 5.0.0)
186
+ rake (> 12.3.3)
187
+ rspec
188
+ simplecov (~> 0.17.1)
189
+ sqlite3
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2019 Colin Petruno
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,289 @@
1
+ # Portunus
2
+
3
+ [![Maintainability](https://api.codeclimate.com/v1/badges/8370f4feb43195c73150/maintainability)](https://codeclimate.com/github/colinpetruno/portunus/maintainability) [![Test Coverage](https://api.codeclimate.com/v1/badges/8370f4feb43195c73150/test_coverage)](https://codeclimate.com/github/colinpetruno/portunus/test_coverage) [![Build Status](https://travis-ci.org/colinpetruno/portunus.svg?branch=master)](https://travis-ci.org/colinpetruno/portunus)
4
+
5
+ Portunus is an opininated, object-oriented encryption engine built for Ruby on Rails
6
+ applications. It utilizes a KEK (Key Encryption Key) & DEK (Data
7
+ Encryption Key) scheme.
8
+
9
+ KEK keys should be stored outside the application. Portunus provides a
10
+ few default adaptors for working with common deployment setups. While this
11
+ is more secure than having unencrypted database data, the best use of
12
+ Portunus would connect to and do the encryption / decryption of your keys
13
+ inside of an HSM. Portunus is easily extensible to accomplish this but it's
14
+ not included due to the extensive variety of possible deployments.
15
+
16
+ Lastly, Portnus has scripts included to do automatic rotation of these keys.
17
+ It's important to rotate both master keys and data encryption keys. Scripts
18
+ are included for both of these that can be scheduled via cron.
19
+ &nbsp;
20
+ ## Background
21
+ Privacy and security need to be considered from the very start of building an
22
+ application. While web development has gotten more accessible, application
23
+ security has not. Portunus is intended to be a drop in utility that requires
24
+ just minutes of set up to ensure your app is using a DEK and KEK encryption
25
+ key to protect your database from several types of attacks. If you want to
26
+ go futher, it's easily extensible for your custom solution.
27
+ &nbsp;
28
+ ## Installation
29
+
30
+ ### Install the gem
31
+
32
+
33
+ $ gem "portunus"
34
+
35
+
36
+ And then execute:
37
+
38
+ $ bundle
39
+
40
+ Or install it yourself as:
41
+
42
+ $ gem install portunus
43
+
44
+ Run the generator. This will create the required Portunus tables.
45
+
46
+ $ rails generate portunus:install
47
+ $ rails db:migrate
48
+
49
+ Include the encryptable module on any of your models or add it to
50
+ `ApplicationRecord` to ensure all your models have access to field encryption.
51
+
52
+ ```ruby
53
+ include Portunus::Encryptable
54
+ ```
55
+
56
+ ### Set up your master keys
57
+ Portunus comes with two adaptors for your master keys, "credentials" and
58
+ "environment". This should cover the most common deploy scenarios. Before
59
+ Portunus can function, enabled master keys need to be added. There is a
60
+ generator to create the keys for you to then install in the proper
61
+ location.
62
+
63
+ $ bundle exec rake portunus:generate_master_keys
64
+
65
+ ### Additional devise notes
66
+
67
+ There is additional configuration required if you are using devise and
68
+ desire to encrypt your email column. Devise will by default downcase email
69
+ addresses. The downcasing performed by devise happens after the portunus
70
+ encryption and result in broken encrypted values. This behaviour needs to
71
+ be disabled from devise and you will need to handle the downcasing prior
72
+ to encryption.
73
+
74
+
75
+ &nbsp;
76
+ ## Basic Configuration
77
+
78
+ To enable encryption on a column, add the `encrypted_fields` method in the
79
+ model and give it the fields you want to encrypt.
80
+
81
+ ```ruby
82
+ class Member < ApplicationRecord
83
+ encrypted_fields :email
84
+ end
85
+ ```
86
+
87
+ ### Database level defaults
88
+
89
+ Since the database does not have access to your encryption engine, default
90
+ values will break the encryption. You need to ensure defaults for encrypted
91
+ columns are set within your application logic.
92
+
93
+
94
+ ### Type casting
95
+
96
+ In order to provide a simpler implementation in your app, Portunus has type
97
+ casting support. The encrypted data must be stored as strings. To utilize
98
+ Portunus with different types, you may specify the type on the field.
99
+
100
+ ```ruby
101
+ class User < ApplicationRecord
102
+ encrypted_fields :email, :firstname, birthdate: { type: :date }
103
+ end
104
+ ```
105
+
106
+ #### Supported types
107
+ - Boolean (:boolean)
108
+ - Date (:date)
109
+ - DateTime (:datetime)
110
+ - Float (:float)
111
+ - Integer (:integer)
112
+ - String (:string) (default)
113
+
114
+
115
+
116
+ ### Hashing
117
+
118
+ Encrypted data cannot be searched. Portunus provides an automatic hash
119
+ mechanism for encrypted data. The hashing happens prior to validation on the
120
+ model and will take your encrypted_field and put it into a column with a name
121
+ of `hashed_encrypted_field`.
122
+
123
+ For instance, a migration for this may look like.
124
+
125
+ ```ruby
126
+ create_table :members do |t|
127
+ t.string :hashed_email, null: false
128
+ t.string :email, null: false
129
+ end
130
+ ```
131
+
132
+ and the model:
133
+
134
+ ```ruby
135
+ class Member < ApplicationRecord
136
+ encrypted_fields :email
137
+ end
138
+ ```
139
+
140
+ #### Portunus::Hasher
141
+ There is a class provided to perform the hashing that you can utilize to look up date.
142
+
143
+ ```ruby
144
+ User.find_by(email: ::Portunus::Hasher.for(params[:email])
145
+ ```
146
+ &nbsp;
147
+ ## Advanced Setup
148
+
149
+ ### Configuration block
150
+ Portunus can be easily customized using a configuration initializer.
151
+
152
+ ```ruby
153
+ Portunus.configuration do |config|
154
+ config.storage_adaptor = Portunus::StorageAdaptors::Credentials
155
+ config.encrypter = Portunus::Encrypters::OpenSslAes
156
+ config.max_key_duration = 1.month
157
+ end
158
+ ```
159
+
160
+ #### Options
161
+ - `storage_adaptor` - This is finds and looks up master keys.
162
+ - `encrypter` - This is responsible for setting the encrypter that encrypts
163
+ decrypts the data.
164
+ - `max_key_duration` - Timeframe for how old you want to allow keys to exist for.
165
+ Ideally your keys are constantly being rotated. Used in key rotation tasks.
166
+
167
+ &nbsp;
168
+ ## Storage adaptors
169
+
170
+ Storage adaptors provide the interface to determine which master key to decrypt
171
+ a data key. Portunus comes with two adaptors to access master keys out of the box.
172
+
173
+ - **Portunus::StorageAdaptors::Environment**
174
+ - **Portunus::StorageAdaptors::Credentials**
175
+
176
+ We need to keep track of the following items:
177
+
178
+ - **Key name** - This is what is stored on the data encryption key table to find the
179
+ master key
180
+ - **Enabled** - Whether the key is enabled for new data keys. Note: If you disable a
181
+ key, that just stops future keys from generating. Until all the keys are rotated,
182
+ do not remove the key.
183
+ - **Created date** - When the key was created to help track rotation duration
184
+
185
+ The master key id is stored on the data key table. These adaptors work like hash
186
+ maps. The key id is passed and a value is returned. The value for both default
187
+ adaptors is the master key. However if you were writing for an environment where keys
188
+ are stored inside an HSM the value could be the key id in the HSM. The encrypter
189
+ would then take that key id and interface with the HSM.
190
+
191
+ Adaptors are easily registered in the config so you can take an existing one
192
+ and customize to your requirements.
193
+
194
+ ### EnvironmentAdaptor
195
+ Store and manage keys through any environment. Great for deployments like
196
+ Heroku. The environment adaptor needs multiple keys per master key to track
197
+ the key value, date created and enabled.
198
+
199
+
200
+ ### Credentials adaptor (default)
201
+ This gets your master keys from your rails credential files. An example
202
+ structure is:
203
+
204
+ ```yaml
205
+ portunus:
206
+ f9e59a8c17c5f430f17745a522ebc2b7:
207
+ key: 93a05a5ce18afb85162a34d552c953b3
208
+ enabled: true
209
+ created_at: "2020-03-13T12:11:11+01:00"
210
+ 140f33e69f0647cbc14b64605f002ff6:
211
+ key: d2c2aa9b7aeff75513ca24efcd8b8dd3
212
+ enabled: true
213
+ created_at: "2020-03-13T12:11:11+01:00"
214
+ ```
215
+ &nbsp;
216
+ ## Key rotation
217
+ Portunus provides key rotation scripts to rotate DEKs, KEKs, and both at
218
+ once. The DEK rotation script will rotate keys every six months. If provided
219
+ a force option as an environment variable it will rotate all the keys. The
220
+ KEK rotation will rotate all master keys. This will probably take a long time
221
+ in many apps so therefore you can rotate the master keys invidually by
222
+ providing the key name.
223
+
224
+
225
+ $ bundle exec rake portunus:rotate_deks
226
+ $ FORCE=true bundle exec rake portunus:rotate_deks
227
+ $ bundle exec rake portunus:rotate_keks
228
+ $ KEY_NAME=<keyname> bundle exec rake portunus:rotate_deks
229
+
230
+ &nbsp;
231
+ ## Tips
232
+ - Security is about applying layers. Using Portunus with the default
233
+ configuration helps protects against specific types of attacks. However, in the
234
+ event your complete environment is compromised there is not much that can
235
+ be done.
236
+ - Providing seperation of concerns within your organization can help if you
237
+ need the data to survive even if someone gets direct server access. Every
238
+ aspect of Portunus is easily configured to ensure this is possible for you.
239
+ - When deciding how many master keys to use, keep the amount of data in mind.
240
+ Each key is responsible for encrypting a certain number of DEKs. The lower
241
+ this is kept the easier it will be to rotate.
242
+ - Schedule rotation often. The dek rotator can be run every day or on even
243
+ smaller intervals.
244
+
245
+
246
+
247
+
248
+ &nbsp;
249
+ ## Improvements
250
+
251
+ Some items I'd like to see added:
252
+
253
+ - Migration support from an unencrypted to encrypted column
254
+ - Google Cloud HSM Encrypter
255
+ - Improve key rotations
256
+ - Research better devise solution.
257
+ - Different encrypters or key sources for different data rows
258
+ - Dashboard to show key usage and which keys can be removed
259
+ - Automatic master key introduction and rotation
260
+
261
+ &nbsp;
262
+ ## Development
263
+
264
+ After checking out the repo, run `bundle install to install dependencies.
265
+
266
+ To install this gem onto your local machine, run `bundle exec rake install`.
267
+ To release a new version, update the version number in `version.rb`, and then
268
+ run `bundle exec rake release`, which will create a git tag for the version,
269
+ push git commits and tags, and push the `.gem` file
270
+ to [rubygems.org](https://rubygems.org).
271
+ &nbsp;
272
+ ## Contributing
273
+
274
+ Bug reports and pull requests are welcome on GitHub at
275
+ https://github.com/colinpetruno/portunus. This project is intended to be a
276
+ safe, welcoming space for collaboration, and contributors are expected to
277
+ adhere to the [Contributor Covenant](http://contributor-covenant.org) code of
278
+ conduct.
279
+ &nbsp;
280
+ ## License
281
+
282
+ The gem is available as open source under the terms of
283
+ the [MIT License](https://opensource.org/licenses/MIT).
284
+ &nbsp;
285
+ ## Code of Conduct
286
+
287
+ Everyone interacting in the Portunus project’s codebases, issue trackers,
288
+ chat rooms and mailing lists is expected to follow
289
+ the [code of conduct](https://github.com/[USERNAME]/portunus/blob/master/CODE_OF_CONDUCT.md).
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "portunus"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/lib/Rakefile ADDED
@@ -0,0 +1,4 @@
1
+ require 'my_gem'
2
+
3
+ path = File.expand_path(__dir__)
4
+ Dir.glob("#{path}/tasks/**/*.rake").each { |f| import f }
@@ -0,0 +1,26 @@
1
+ require 'rails/generators'
2
+ require 'rails/generators/migration'
3
+ require "rails/generators/active_record/migration"
4
+
5
+ module Portunus
6
+ module Generators
7
+ class InstallGenerator < Rails::Generators::Base
8
+ include ActiveRecord::Generators::Migration
9
+
10
+ source_root File.expand_path("templates", __dir__)
11
+ desc "Add the migrations for Porteus"
12
+
13
+ def copy_migrations
14
+ warn "Creating Migrations for Portunus Encryption"
15
+ migration_template(
16
+ "create_portunus.rb.erb",
17
+ "db/migrate/create_portunus.rb"
18
+ )
19
+ end
20
+
21
+ def migration_version
22
+ "[#{Rails::VERSION::MAJOR}.#{Rails::VERSION::MINOR}]"
23
+ end
24
+ end
25
+ end
26
+ end