Skip to content

Commit

Permalink
Merge pull request #4 from itk-dev/feature/hashi-corp-vault
Browse files Browse the repository at this point in the history
Added HashiCorp vault key provider
  • Loading branch information
jekuaitk authored Jan 20, 2025
2 parents e2b0eb2 + 9baf9fc commit df3ba03
Show file tree
Hide file tree
Showing 27 changed files with 1,554 additions and 47 deletions.
35 changes: 32 additions & 3 deletions .github/workflows/pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
php-versions: [ '8.1' ]
php-versions: [ '8.3' ]
dependency-version: [ prefer-lowest, prefer-stable ]
steps:
- uses: actions/checkout@master
Expand Down Expand Up @@ -58,7 +58,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
php-versions: [ '8.1' ]
php-versions: [ '8.3' ]
steps:
- uses: actions/checkout@master
- name: Setup PHP, with composer and extensions
Expand Down Expand Up @@ -90,7 +90,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
php-versions: [ '8.1' ]
php-versions: [ '8.3' ]
steps:
- uses: actions/checkout@master
- name: Setup PHP, with composer and extensions
Expand All @@ -114,6 +114,35 @@ jobs:
run: |
./scripts/code-analysis
php-unit-tests:
name: PHP unit tests
runs-on: ubuntu-latest
strategy:
matrix:
php-versions: [ '8.3' ]
steps:
- uses: actions/checkout@master
- name: Setup PHP, with composer and extensions
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php-versions }}
extensions: json
coverage: none
tools: composer:v2
# https://github.com/shivammathur/setup-php#cache-composer-dependencies
- name: Get composer cache directory
id: composer-cache
run: echo "::set-output name=dir::$(composer config cache-files-dir)"
- name: Cache dependencies
uses: actions/cache@v2
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
restore-keys: ${{ runner.os }}-composer-
- name: Unit tests
run: |
./scripts/unit-tests
coding-standards-markdown:
name: Markdown coding standards
runs-on: ubuntu-latest
Expand Down
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

* [PR-4](https://github.com/OS2web/os2web_key/pull/4)
Added HashiCorp Vault key provider
* [PR-2](https://github.com/OS2web/os2web_key/pull/2)
Updated documentation
* [PR-1](https://github.com/OS2web/os2web_key/pull/1)
Expand Down
91 changes: 81 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
Key types and providers for OS2Web built on the [Key module](https://www.drupal.org/project/key).

The OS2Web key module provides two _key types_, [Certificate](#certificate) and [OpenID Connect
(OIDC)](#openid-connect-oidc). Two _key providers_, [Azure Key Vault](#azure-key-vault) and [Infisical](#infisical), are
planned, but not yet implemented.
(OIDC)](#openid-connect-oidc). It also comes with two _key providers_,
[Azure Key Vault](#azure-key-vault) and [HashiCorp Vault](#hashicorp-vault).

See [the Key Developer Guide](https://www.drupal.org/docs/contributed-modules/key/developer-guide) for details in how to
use keys in Drupal.
Expand Down Expand Up @@ -106,13 +106,24 @@ $key = $repository->getKey('openid_connect_ad');

## Providers

The module comes with two key providers.

### Azure Key Vault

`@todo` <https://azure.microsoft.com/en-us/products/key-vault>
Used for fetching certificate from Azure Key vault.

### HashiCorp Vault

### Infisical
Used to fetch any sort of secret string from HashiCorp vault. Note that
this can only provide string values, i.e. no binary files.

`@todo` <https://infisical.com/>
To use this provider you must configure the following in `settings.local.php`:

``` php
$settings['os2web_vault_role_id'] = '{ROLE_ID}';
$settings['os2web_vault_secret_id'] = '{SECRET_ID}';
$settings['os2web_vault_url'] = '{VAULT_URL}';
```

## Coding standards

Expand All @@ -122,11 +133,11 @@ below to run the checks locally.
### PHP

```shell
docker run --rm --volume ${PWD}:/app --workdir /app itkdev/php8.1-fpm composer install
docker run --rm --volume ${PWD}:/app --workdir /app itkdev/php8.3-fpm composer install
# Fix (some) coding standards issues
docker run --rm --volume ${PWD}:/app --workdir /app itkdev/php8.1-fpm composer coding-standards-apply
docker run --rm --volume ${PWD}:/app --workdir /app itkdev/php8.3-fpm composer coding-standards-apply
# Check that code adheres to the coding standards
docker run --rm --volume ${PWD}:/app --workdir /app itkdev/php8.1-fpm composer coding-standards-check
docker run --rm --volume ${PWD}:/app --workdir /app itkdev/php8.3-fpm composer coding-standards-check
```

### Markdown
Expand All @@ -140,9 +151,69 @@ docker run --rm --volume $PWD:/md peterdavehello/markdownlint markdownlint --ign

We use [PHPStan](https://phpstan.org/) for static code analysis.

Running statis code analysis on a standalone Drupal module is a bit tricky, so we use a helper script to run the
Running static code analysis on a standalone Drupal module is a bit tricky, so we use a helper script to run the
analysis:

```shell
docker run --rm --volume ${PWD}:/app --workdir /app itkdev/php8.3-fpm ./scripts/code-analysis
```

## Unit tests

We use [PHPUnit](https://phpunit.de/documentation.html) for unit testing.

Testing mostly centers around the conversion and parsing of certificates. For this purpose a bunch of test
certificates has been generated. See [Test certificates](#test-certificates) for how this is done.

Running PHPUnit tests in a standalone Drupal module is a bit tricky, so we use a helper script to run the
analysis:

```shell
docker run --rm --volume ${PWD}:/app --workdir /app itkdev/php8.1-fpm ./scripts/code-analysis
docker run --rm --volume ${PWD}:/app --workdir /app itkdev/php8.3-fpm ./scripts/unit-tests
```

### Test certificates

Certificates have been generated in the follow way

```shell
# p12 with password
openssl req -x509 -newkey rsa:4096 -days 365 -subj "/CN=example.com" -passout pass:test -keyout test.key -out test.crt
openssl pkcs12 -export -out test_with_passphrase.p12 -passin pass:test -passout pass:test -inkey test.key -in test.crt
openssl pkcs12 -in test_with_passphrase.p12 -passin pass:test -noenc

# p12 without password
openssl req -x509 -newkey rsa:4096 -days 365 -subj "/CN=example.com" -passout pass:'' -keyout test_without_passphrase.key -out test_without_passphrase.crt
openssl pkcs12 -export -out test_without_passphrase.p12 -passin pass:'' -passout pass:'' -inkey test_without_passphrase.key -in test_without_passphrase.crt
openssl pkcs12 -in test_without_passphrase.p12 -passin pass:'' -noenc

# PEM with password
openssl req -x509 -newkey rsa:4096 -days 365 -subj "/CN=example.com" -passout pass:test -keyout test.key -out test.crt
cat test.crt test.key > test_with_passphrase.pem
openssl x509 -in test_with_passphrase.pem

# PEM without password
openssl req -x509 -newkey rsa:4096 -days 365 -subj "/CN=example.com" -passout pass:'' -keyout test_without_passphrase.key -out test_without_passphrase.crt -noenc
cat test_without_passphrase.crt test_without_passphrase.key > test_without_passphrase.pem
openssl x509 -in test_without_passphrase.pem
```

Extraction of certificate and private key parts in the following way

```shell
# P12 with passphrase
openssl pkcs12 -in test_with_passphrase.p12 -passin pass:test -clcerts -nokeys | sed -ne '/-----BEGIN CERTIFICATE-----/,/-----END CERTIFICATE-----/p' > p12_with_passphrase_cert.txt
openssl pkcs12 -in test_with_passphrase.p12 -passin pass:test -nocerts -nodes | sed -ne '/-----BEGIN PRIVATE KEY-----/,/-----END PRIVATE KEY-----/p' > p12_with_passphrase_pkey.txt

# P12 without passphrase
openssl pkcs12 -in test_without_passphrase.p12 -passin pass: -clcerts -nokeys | sed -ne '/-----BEGIN CERTIFICATE-----/,/-----END CERTIFICATE-----/p' > p12_without_passphrase_cert.txt
openssl pkcs12 -in test_without_passphrase.p12 -passin pass: -nocerts -nodes | sed -ne '/-----BEGIN PRIVATE KEY-----/,/-----END PRIVATE KEY-----/p' > p12_without_passphrase_pkey.txt

# PEM with passphrase
openssl x509 -in test_with_passphrase.pem -passin pass:test -out pem_with_passphrase_cert.txt
openssl pkey -in test_with_passphrase.pem -passin pass:test -out pem_with_passphrase_pkey.txt

# PEM without passphrase
openssl x509 -in test_without_passphrase.pem -passin pass: -out pem_without_passphrase_cert.txt
openssl pkey -in test_without_passphrase.pem -passin pass: -out pem_without_passphrase_pkey.txt
```
13 changes: 11 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,22 +13,31 @@
"php": "^8.1",
"ext-openssl": "*",
"drupal/core": "^9 || ^10",
"drupal/key": "^1.17"
"drupal/key": "^1.17",
"itk-dev/serviceplatformen": "^1.6",
"itk-dev/vault": "^0.1"
},
"require-dev": {
"dealerdirect/phpcodesniffer-composer-installer": "^1.0",
"drupal/coder": "^8.3",
"drupal/core-dev": "^9 || ^10",
"ergebnis/composer-normalize": "^2.42",
"mglaman/phpstan-drupal": "^1.2",
"phpstan/extension-installer": "^1.3",
"phpstan/phpstan-deprecation-rules": "^1.1"
"phpstan/phpstan-deprecation-rules": "^1.1",
"phpunit/phpunit": "^9.6"
},
"repositories": [
{
"type": "composer",
"url": "https://packages.drupal.org/8"
}
],
"autoload-dev": {
"psr-4": {
"Drupal\\Tests\\os2web_key\\": "tests/src/"
}
},
"config": {
"allow-plugins": {
"dealerdirect/phpcodesniffer-composer-installer": true,
Expand Down
8 changes: 7 additions & 1 deletion os2web_key.services.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,11 @@ services:
arguments: [ 'os2web_key' ]

Drupal\os2web_key\KeyHelper:
autowire: true
arguments:
- '@logger.channel.os2web_key'
$logger: '@logger.channel.os2web_key'

Drupal\os2web_key\Services\Psr16CacheAdapter:
autowire: true
arguments:
$cacheBackend: '@cache.default'
29 changes: 13 additions & 16 deletions scripts/code-analysis
Original file line number Diff line number Diff line change
Expand Up @@ -11,37 +11,34 @@ drupal_composer() {
composer --working-dir="$drupal_dir" --no-interaction "$@"
}

# Create new Drupal 9 project
# Create new Drupal 10 project
if [ ! -f "$drupal_dir/composer.json" ]; then
composer --no-interaction create-project drupal/recommended-project:^9 "$drupal_dir"
composer --no-interaction create-project drupal/recommended-project:^10 "$drupal_dir"
fi
# Copy our code into the modules folder

# Clean up
rm -fr "${drupal_dir:?}/$module_path"

mkdir -p "$drupal_dir/$module_path"
# https://stackoverflow.com/a/15373763
# rsync --archive --compress . --filter=':- .gitignore' --exclude "$drupal_dir" --exclude .git "$drupal_dir/$module_path"

# The rsync command in not available in itkdev/php8.1-fpm

git config --global --add safe.directory /app
# Copy module files into module path
for f in $(git ls-files); do
mkdir -p "$drupal_dir/$module_path/$(dirname "$f")"
cp "$f" "$drupal_dir/$module_path/$f"
done
rsync --archive --compress . --filter=':- .gitignore' --exclude "$drupal_dir" --exclude .git "$drupal_dir/$module_path"

drupal_composer config minimum-stability dev

drupal_composer --append repositories.os2web/os2web_key path "$module_path"

# Allow ALL plugins
# https://getcomposer.org/doc/06-config.md#allow-plugins
drupal_composer config --no-plugins allow-plugins true

# Making Drupal 10 compatible
drupal_composer require psr/http-message:^1.0
drupal_composer require mglaman/composer-drupal-lenient
drupal_composer config --merge --json extra.drupal-lenient.allowed-list '["drupal/coc_forms_auto_export", "drupal/webform_node_element"]'

drupal_composer require wikimedia/composer-merge-plugin
drupal_composer config extra.merge-plugin.include "$module_path/composer.json"
# https://www.drupal.org/project/drupal/issues/3220043#comment-14845434
drupal_composer require --dev symfony/phpunit-bridge
drupal_composer --no-interaction install


# Run PHPStan
(cd "$drupal_dir/$module_path" && ../../../../vendor/bin/phpstan)
43 changes: 43 additions & 0 deletions scripts/unit-tests
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#!/usr/bin/env bash
script_dir=$(pwd)
module_name=$(basename "$script_dir")
drupal_dir=vendor/drupal-module-unit-tests-analysis
# Relative to $drupal_dir
module_path=web/modules/contrib/$module_name

cd "$script_dir" || exit

drupal_composer() {
composer --working-dir="$drupal_dir" --no-interaction "$@"
}

# Create new Drupal 10 project
if [ ! -f "$drupal_dir/composer.json" ]; then
composer --no-interaction create-project drupal/recommended-project:^10 "$drupal_dir"
fi
# Copy our code into the modules folder
mkdir -p "$drupal_dir/$module_path"
# https://stackoverflow.com/a/15373763
rsync --archive --compress . --filter=':- .gitignore' --exclude "$drupal_dir" --exclude .git "$drupal_dir/$module_path"

drupal_composer config minimum-stability dev

drupal_composer --append repositories.os2web/os2web_key path "$module_path"

# Allow ALL plugins
# https://getcomposer.org/doc/06-config.md#allow-plugins
drupal_composer config --no-plugins allow-plugins true

# Making Drupal 10 compatible
drupal_composer require psr/http-message:^1.0
drupal_composer require mglaman/composer-drupal-lenient
drupal_composer config --merge --json extra.drupal-lenient.allowed-list '["drupal/coc_forms_auto_export", "drupal/webform_node_element"]'

drupal_composer require wikimedia/composer-merge-plugin
drupal_composer config extra.merge-plugin.include "$module_path/composer.json"
# https://www.drupal.org/project/drupal/issues/3220043#comment-14845434
drupal_composer require --dev symfony/phpunit-bridge
drupal_composer --no-interaction install

# Run PHPUnit
(cd "$drupal_dir" && vendor/bin/phpunit --configuration web/core/phpunit.xml.dist "$module_path/tests/src/Unit/KeyHelperUnitTest.php")
10 changes: 10 additions & 0 deletions src/Exception/Exception.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

namespace Drupal\os2web_key\Exception;

/**
* OS2Web key base exception.
*/
class Exception extends \Exception {

}
10 changes: 10 additions & 0 deletions src/Exception/FileException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

namespace Drupal\os2web_key\Exception;

/**
* File exception.
*/
class FileException extends Exception {

}
Loading

0 comments on commit df3ba03

Please sign in to comment.