Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Managed identity #2

Merged
merged 73 commits into from
Sep 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
73 commits
Select commit Hold shift + click to select a range
bc7b330
Version bump
JoeDupuis Jun 7, 2024
29a99a2
Make Signer#sign private
dan-corneanu Jun 7, 2024
f9360b9
Add support for additional MSI config options
dan-corneanu Jun 10, 2024
0f3d8df
Implement a MSI token provider
dan-corneanu Jun 10, 2024
ecbdff9
Refactor to extract signer config params out of Client
dan-corneanu Jun 10, 2024
345f210
no message
dan-corneanu Jun 10, 2024
2941103
Implement EntraIdSigner#sas_token
dan-corneanu Jun 10, 2024
2801fbb
Remove section on Managed Identity internals
dan-corneanu Jun 12, 2024
b8e2a86
Let the Client figure out which signer to instantiate
dan-corneanu Jun 12, 2024
f8aa557
Merge pull request #1 from dan-corneanu/managed_identity
JoeDupuis Jul 17, 2024
2fda93d
Merge branch 'main' into managed_identity
JoeDupuis Jul 25, 2024
e747b06
Remove an active support reference
JoeDupuis Aug 15, 2024
cfa9f84
Script to generate the devenv.local.nix file
JoeDupuis Aug 15, 2024
70ca9cc
Script to rsync the working directory to the test vm
JoeDupuis Aug 15, 2024
f01826c
Use the default ruby to avoid long rebuild on the vm
JoeDupuis Aug 15, 2024
8a43c98
Add VM support
JoeDupuis Aug 15, 2024
579aa40
Use a azurerm_linux_virtual_machine block instead
JoeDupuis Aug 15, 2024
e297175
Remove deads code
JoeDupuis Aug 16, 2024
d91c4cc
Attach role to the vm
JoeDupuis Aug 16, 2024
3ac644b
Exclude the terraform folder
JoeDupuis Aug 16, 2024
8830281
Remove glibc
JoeDupuis Aug 18, 2024
0ff29d1
Set LD_LIBRARY_PATH for FFI
JoeDupuis Aug 18, 2024
71aaaeb
Ignore some terraform files
JoeDupuis Aug 18, 2024
6dd25bf
Set the role on the account instead of the containers
JoeDupuis Aug 19, 2024
a6e0e0d
Remove unused require
JoeDupuis Aug 23, 2024
b843a2d
Remove Signer documentation (private API)
JoeDupuis Aug 23, 2024
198ec29
Use stock ruby
JoeDupuis Sep 3, 2024
7cdbb16
Add nix2container and mk-shell-bin
JoeDupuis Sep 3, 2024
fe3751d
Can't have nice things
JoeDupuis Sep 4, 2024
76157a6
sshuttle
JoeDupuis Sep 4, 2024
3fd0fa7
Update bundler and stringio
JoeDupuis Sep 4, 2024
d97e54d
No need for cloud config with sshuttle
JoeDupuis Sep 4, 2024
0aedc9e
vps proxy script
JoeDupuis Sep 4, 2024
440eef3
Rake task to test with entra id
JoeDupuis Sep 4, 2024
6a19fdb
VPS instructions
JoeDupuis Sep 4, 2024
98540ba
Create an app service app
JoeDupuis Sep 5, 2024
3b7e70a
Put public key in local
JoeDupuis Sep 5, 2024
da979b0
Establish VPN to App Service
JoeDupuis Sep 7, 2024
74e3250
Temp support for both app service and VM
JoeDupuis Sep 7, 2024
55dfc7b
Kill the vpn
JoeDupuis Sep 7, 2024
487e5b7
Allow setting the role principal id
JoeDupuis Sep 7, 2024
1f8d373
Auto start the azure vm vpn
JoeDupuis Sep 7, 2024
35e95ff
Ensure vpn kill
JoeDupuis Sep 8, 2024
7b97763
Wait for the vpn to connect
JoeDupuis Sep 8, 2024
8a6efcd
Do not expose the token to the client
JoeDupuis Sep 8, 2024
b7a3188
Refactor the msi token provider
JoeDupuis Sep 8, 2024
3f3aacf
Extract user delegation key
JoeDupuis Sep 8, 2024
024c55e
Minitest fail fast
JoeDupuis Sep 8, 2024
e0145a7
Try sigint instead of kill
JoeDupuis Sep 8, 2024
afaac93
Ensure we don't load rails before running the client tests
JoeDupuis Sep 8, 2024
4c7d2fb
Exec the proxy commands
JoeDupuis Sep 8, 2024
5f2edf5
Fix missing require
JoeDupuis Sep 8, 2024
48940b4
Extract delegation key from the sas_token method
JoeDupuis Sep 8, 2024
ae53cc2
Consistency
JoeDupuis Sep 8, 2024
7e95ade
Fix expiration buffer
JoeDupuis Sep 9, 2024
9f97768
Test identity token and user delegation key
JoeDupuis Sep 9, 2024
17b4474
Exponential backoff
JoeDupuis Sep 9, 2024
1f56a0d
Managed identity readme
JoeDupuis Sep 9, 2024
117927a
Test with the minimum ruby version
JoeDupuis Sep 9, 2024
c9857fe
Enforce MFA
JoeDupuis Sep 9, 2024
f21e939
Lint
JoeDupuis Sep 9, 2024
040a52d
Replace echo with printf
JoeDupuis Sep 9, 2024
04da4d3
Ensure the client code was tested without Rails
JoeDupuis Sep 9, 2024
81af788
Fix a typo in the doc
JoeDupuis Sep 9, 2024
2b4dc03
Spacing
JoeDupuis Sep 9, 2024
9cea737
Grammar
JoeDupuis Sep 9, 2024
56b7561
Simplify the managed id instructions
JoeDupuis Sep 9, 2024
6a9d316
Lint
JoeDupuis Sep 10, 2024
7a3a06c
Not building containers yet
JoeDupuis Sep 10, 2024
695c544
Remove unused script
JoeDupuis Sep 10, 2024
9d9bbba
Simplify instructions
JoeDupuis Sep 10, 2024
705b0ce
Spacing
JoeDupuis Sep 10, 2024
c5b28a7
Lint
JoeDupuis Sep 10, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,6 @@ devenv.local.nix

/.terraform
terraform.tfstate
terraform.tfstate.backup
terraform.tfstate.backup
.terraform.tfstate.lock.info
*.tfvars
6 changes: 6 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ gemspec
gem "rake"

gem "minitest"
gem "minitest-fail-fast"

gem "rubocop-rails-omakase"

Expand All @@ -19,3 +20,8 @@ gem "rails", github: "rails/rails", branch: "main"
gem "propshaft", ">= 0.1.7"
gem "image_processing", "~> 1.2"
gem "sqlite3", ">= 1.6.6"


gem "net-ssh"
gem "ed25519"
gem "bcrypt_pbkdf"
18 changes: 16 additions & 2 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@ GEM
specs:
ast (2.4.2)
base64 (0.2.0)
bcrypt_pbkdf (1.1.1)
bcrypt_pbkdf (1.1.1-arm64-darwin)
bigdecimal (3.1.8)
builder (3.2.4)
concurrent-ruby (1.2.3)
Expand All @@ -115,6 +117,7 @@ GEM
irb (~> 1.10)
reline (>= 0.3.8)
drb (2.2.1)
ed25519 (1.3.0)
erubi (1.12.0)
ffi (1.16.3)
globalid (1.2.1)
Expand Down Expand Up @@ -142,6 +145,8 @@ GEM
mini_magick (4.12.0)
mini_mime (1.1.5)
minitest (5.23.1)
minitest-fail-fast (0.1.0)
minitest (~> 5)
net-imap (0.4.11)
date
net-protocol
Expand All @@ -151,7 +156,10 @@ GEM
timeout
net-smtp (0.5.0)
net-protocol
net-ssh (7.2.3)
nio4r (2.7.3)
nokogiri (1.16.5-arm64-darwin)
racc (~> 1.4)
nokogiri (1.16.5-x86_64-linux)
racc (~> 1.4)
parallel (1.24.0)
Expand Down Expand Up @@ -222,8 +230,9 @@ GEM
ruby-progressbar (1.13.0)
ruby-vips (2.2.1)
ffi (~> 1.12)
sqlite3 (2.0.2-arm64-darwin)
sqlite3 (2.0.2-x86_64-linux-gnu)
stringio (3.1.0)
stringio (3.1.1)
strscan (3.1.0)
thor (1.3.1)
timeout (0.4.1)
Expand All @@ -238,18 +247,23 @@ GEM
zeitwerk (2.6.14)

PLATFORMS
arm64-darwin-23
x86_64-linux

DEPENDENCIES
azure-blob!
bcrypt_pbkdf
debug
ed25519
image_processing (~> 1.2)
minitest
minitest-fail-fast
net-ssh
propshaft (>= 0.1.7)
rails!
rake
rubocop-rails-omakase
sqlite3 (>= 1.6.6)

BUNDLED WITH
2.4.22
2.5.9
58 changes: 50 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,37 @@ This gem was built to replace azure-storage-blob (deprecated) in Active Storage,

## Active Storage

## Migration
### Migration
To migrate from azure-storage-blob to azure-blob:

1. Replace `azure-storage-blob` in your Gemfile with `azure-blob`
2. Run `bundle install`
3. Change the `AzureStorage` service to `AzureBlob` in your Active Storage config (`config/storage.yml`)
4. Restart or deploy the app.

### Managed Identity (Entra ID)

AzureBlob supports managed identities on :
- Azure VM
- App Service
- Azure Functions (Untested but should work)
- Azure Containers (Untested but should work)

AKS support will likely require more work. Contributions are welcome.

To authenticate through managed identities instead of a shared key, omit `storage_access_key` from your `storage.yml` file.

It is recommended to add the identity's `principal_id` to the config.

ActiveStorage config example:

```
prod:
service: AzureBlob
container: container_name
storage_account_name: account_name
principal_id: 71b34410-4c50-451d-b456-95ead1b18cce
```

## Standalone

Expand Down Expand Up @@ -48,10 +71,34 @@ A dev environment is supplied through Nix with [devenv](https://devenv.sh/).
2. Enter the dev environment by cd into the repo and running `devenv shell` (or `direnv allow` if you are a direnv user).
3. Log into azure CLI with `az login`
4. `terraform init`
5. `terraform apply` This will generate the necessary infrastructure on azure
6. Generate devenv.local.nix with your private key and container information: `terraform output -raw devenv_local_nix > devenv.local.nix`
5. `terraform apply` This will generate the necessary infrastructure on azure.
6. Generate devenv.local.nix with your private key and container information: `generate-env-file`
7. If you are using direnv, the environment will reload automatically. If not, exit the shell and reopen it by hitting <C-d> and running `devenv shell` again.

#### Entra ID

To test with Entra ID, the `AZURE_ACCESS_KEY` environment variable must be unset and the code must be ran or proxied through a VPS with the proper roles.

For cost saving, the terraform variable `create_vm` is false by default.
To create the VPS, Create a var file `var.tfvars` containing:

```
create_vm = true
```
and re-apply terraform: `terraform apply -var-file=var.tfvars`.

This will create the VPS and required managed identities.

`bin/rake test_azure_vm` and `bin/rake test_app_service` will establish a VPN connection to the VM or App service container and run the test suite. You might be prompted for a sudo password when the VPN starts (sshuttle).

After you are done, run terraform again without the var file (`terraform apply`) to destroy the VPS and App service application.

#### Cleanup

Some tests copied over from Rails don't clean after themselves. A rake task is provided to empty your containers and keep cost low: `bin/rake flush_test_container`

#### Run without devenv/nix

If you prefer not using devenv/nix:

Ensure your version of Ruby fit the minimum version in `azure-blob.gemspec`
Expand All @@ -63,11 +110,6 @@ and setup those Env variables:
- `AZURE_PRIVATE_CONTAINER`
- `AZURE_PUBLIC_CONTAINER`


### Tests

`bin/rake test`

## License

The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
44 changes: 40 additions & 4 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,57 @@

require "bundler/gem_tasks"
require "minitest/test_task"
require 'azure_blob'
require "azure_blob"
require_relative "test/support/app_service_vpn"
require_relative "test/support/azure_vm_vpn"

Minitest::TestTask.create
Minitest::TestTask.create(:test_rails) do
self.test_globs = [ "test/rails/**/test_*.rb",
"test/rails/**/*_test.rb", ]
end

Minitest::TestTask.create(:test_client) do
self.test_globs = [ "test/client/**/test_*.rb",
"test/client/**/*_test.rb", ]
end

task default: %i[test]

task :test do
Rake::Task["test_client"].execute
Rake::Task["test_rails"].execute
end

task :test_app_service do |t|
vpn = AppServiceVpn.new
ENV["IDENTITY_ENDPOINT"] = vpn.endpoint
ENV["IDENTITY_HEADER"] = vpn.header
Rake::Task["test_entra_id"].execute
ensure
vpn.kill
end

task :test_azure_vm do |t|
vpn = AzureVmVpn.new
Rake::Task["test_entra_id"].execute
ensure
vpn.kill
end

task :test_entra_id do |t|
ENV["AZURE_ACCESS_KEY"] = nil
Rake::Task["test"].execute
end

task :flush_test_container do |t|
AzureBlob::Client.new(
account_name: ENV["AZURE_ACCOUNT_NAME"],
access_key: ENV["AZURE_ACCESS_KEY"],
container: ENV["AZURE_PRIVATE_CONTAINER"],
).delete_prefix ''
).delete_prefix ""
AzureBlob::Client.new(
account_name: ENV["AZURE_ACCOUNT_NAME"],
access_key: ENV["AZURE_ACCESS_KEY"],
container: ENV["AZURE_PUBLIC_CONTAINER"],
).delete_prefix ''
).delete_prefix ""
end
1 change: 1 addition & 0 deletions azure-blob.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ Gem::Specification.new do |spec|
spec.license = "MIT"
spec.required_ruby_version = ">= 3.1"

spec.metadata["rubygems_mfa_required"] = "true"
spec.metadata["homepage_uri"] = spec.homepage
spec.metadata["source_code_uri"] = spec.homepage
spec.metadata["changelog_uri"] = "https://github.com/testdouble/azure-blob/blob/main/CHANGELOG.md"
Expand Down
22 changes: 11 additions & 11 deletions devenv.lock
Original file line number Diff line number Diff line change
Expand Up @@ -108,16 +108,16 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1715542476,
"lastModified": 1725001927,
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "44072e24566c5bcc0b7aa9178a0104f4cfffab19",
"treeHash": "3f9021e4c33de6fe59b88ac8c3019fc49136dc2a",
"rev": "6e99f2a27d600612004fbd2c3282d614bfee6421",
"treeHash": "1e85443cc9f0ba302df2cf61cacb8014943e2d19",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-23.11",
"ref": "nixos-24.05",
"repo": "nixpkgs",
"type": "github"
}
Expand All @@ -129,11 +129,11 @@
"nixpkgs": "nixpkgs_2"
},
"locked": {
"lastModified": 1713939467,
"lastModified": 1724737223,
"owner": "bobvanderlinden",
"repo": "nixpkgs-ruby",
"rev": "c1ba161adf31119cfdbb24489766a7bcd4dbe881",
"treeHash": "0d32620317b29f94d6718684f030dd2fc2f30cb2",
"rev": "175b5867babcbc471b94be9fd5576f2973bbdb6d",
"treeHash": "2fe3404ac0eeb7bcb7ac7b5f5f8b9b6a7e460147",
"type": "github"
},
"original": {
Expand All @@ -160,16 +160,16 @@
},
"nixpkgs_2": {
"locked": {
"lastModified": 1715542476,
"lastModified": 1725001927,
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "44072e24566c5bcc0b7aa9178a0104f4cfffab19",
"treeHash": "3f9021e4c33de6fe59b88ac8c3019fc49136dc2a",
"rev": "6e99f2a27d600612004fbd2c3282d614bfee6421",
"treeHash": "1e85443cc9f0ba302df2cf61cacb8014943e2d19",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-23.11",
"ref": "nixos-24.05",
"repo": "nixpkgs",
"type": "github"
}
Expand Down
28 changes: 25 additions & 3 deletions devenv.nix
Original file line number Diff line number Diff line change
@@ -1,14 +1,36 @@
{ pkgs, ... }:
{ pkgs, config, ... }:

{
env = {
LD_LIBRARY_PATH = "${config.devenv.profile}/lib";
};

packages = with pkgs; [
git
libyaml
terraform
azure-cli
glib
vips
sshuttle
sshpass
rsync
];


languages.ruby.enable = true;
languages.ruby.version = "3.1.5";
languages.ruby.version = "3.1.6";

scripts.generate-env-file.exec = ''
terraform output -raw devenv_local_nix > devenv.local.nix
'';

scripts.proxy-vps.exec = ''
exec sshuttle -e "ssh -o CheckHostIP=no -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" -r "$(terraform output --raw vm_username)@$(terraform output --raw vm_ip)" 0/0
'';

scripts.start-app-service-ssh.exec = ''
resource_group=$(terraform output --raw "resource_group")
app_name=$(terraform output --raw "app_service_app_name")
exec az webapp create-remote-connection --resource-group $resource_group --name $app_name
'';
}
2 changes: 1 addition & 1 deletion devenv.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
allowUnfree: true
inputs:
nixpkgs:
url: github:NixOS/nixpkgs/nixos-23.11
url: github:NixOS/nixpkgs/nixos-24.05
nixpkgs-ruby:
url: github:bobvanderlinden/nixpkgs-ruby
Loading
Loading