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

Merge spire-api feature branch into main #46

Merged
merged 4 commits into from
Aug 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 5 additions & 1 deletion .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ updates:
schedule:
interval: "daily"
- package-ecosystem: "cargo"
directory: "/" # Location of the Cargo.toml file
directory: "/spiffe" # Location of the Cargo.toml file for spiffe crate
schedule:
interval: "daily"
- package-ecosystem: "cargo"
directory: "/spire-api" # Location of the Cargo.toml file for spire-api crate
schedule:
interval: "daily"
18 changes: 17 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ jobs:
steps:
- name: Check out code
uses: actions/checkout@v3
with:
submodules: recursive
- name: Install dependencies and common setup
uses: ./.github/actions/setup-env
- name: Lint Rust code with rustfmt and clippy
Expand All @@ -23,25 +25,39 @@ jobs:
steps:
- name: Check out code
uses: actions/checkout@v3
with:
submodules: recursive
- name: Install dependencies and common setup
uses: ./.github/actions/setup-env
- name: Build Rust project
run: cargo build

test:
name: Run SPIFFE Integration Tests
name: Run spiffe and spire-api Integration Tests
runs-on: ubuntu-latest
env:
SPIFFE_ENDPOINT_SOCKET: unix:/tmp/spire-agent/public/api.sock
SPIRE_ADMIN_ENDPOINT_SOCKET: unix:/tmp/spire-agent/admin/api.sock
needs: build
steps:
- name: Check out code
uses: actions/checkout@v3
with:
submodules: recursive

- name: Install dependencies and common setup
uses: ./.github/actions/setup-env

- name: Start SPIRE
run: ./scripts/run-spire.sh &

- name: Execute spiffe Integration Tests
run: RUST_BACKTRACE=1 cargo test --features integration-tests
working-directory: spiffe

- name: Execute spire-api Integration Tests
run: RUST_BACKTRACE=1 cargo test --features integration-tests
working-directory: spire-api

- name: Clean up SPIRE
run: ./scripts/cleanup-spire.sh
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
Cargo.lock
**/Cargo.lock

# These are backup files generated by rustfmt
**/*.rs.bk
Expand Down
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "spire-api-sdk"]
path = spire-api-sdk
url = https://github.com/spiffe/spire-api-sdk.git
57 changes: 5 additions & 52 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,52 +1,5 @@
[package]
edition = "2018"
name = "spiffe"
# When releasing to crates.io:
# - Update CHANGELOG.md.
# - Create a new tag
version = "0.3.1"
authors = ["Max Lambrecht <maxlambrecht@gmail.com>"]
description = "Rust client library implementation for SPIFFE"
license = "Apache-2.0"
repository = "https://github.com/maxlambrecht/rust-spiffe"
documentation = "https://docs.rs/spiffe"
readme = "README.md"
categories = ["cryptography"]
keywords = ["SPIFFE", "X509", "JWT"]

[dependencies]
tonic = { version = "0.9", default-features = false, features = ["prost", "codegen", "transport"]}
prost = { version = "0.11"}
prost-types = {version = "0.11"}
tokio = { "version" = "1", features = ["net", "test-util"]}
tokio-stream = "0.1"
tower = { version = "0.4", features = ["util"] }
thiserror = "1.0"
url = "2.2"
asn1 = { package = "simple_asn1", version = "0.6" }
x509-parser = "0.15"
pkcs8 = "0.10"
jsonwebtoken = "8.3"
jsonwebkey = { version = "0.3", features = ["jsonwebtoken", "jwt-convert"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
zeroize = { version = "1.6", features = ["zeroize_derive"] }
time = "0.3"


[dev-dependencies]
jsonwebkey = { version = "0.3", features = ["generate"] }
tokio-test = "0.4"
once_cell = "1.18"

# used to verify in tests that the certificates bytes from the X.509 SVIDs and bundle authorities
# are parseable as OpenSSL X.509 certificates.
openssl = { version = "0.10", features = ["vendored"] }

[build-dependencies]
tonic-build = { version = "0.9", default-features = false, features = ["prost"] }
prost-build = "0.11"
anyhow = "1.0.65"

[features]
integration-tests = []
[workspace]
members = [
"spiffe",
"spire-api",
]
139 changes: 16 additions & 123 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,134 +1,27 @@
# Rust SPIFFE Library
# Rust SPIRE Libraries

This utility library enables interaction with the [SPIFFE Workload API](https://github.com/spiffe/spiffe/blob/main/standards/SPIFFE_Workload_API.md). It allows fetching of X.509 and JWT SVIDs, bundles and supports watch/stream updates. The types in the library are in compliance with [SPIFFE standards](https://github.com/spiffe/spiffe/tree/main/standards). More about SPIFFE can be found at [spiffe.io](https://spiffe.io/).
This repository contains two distinct Rust libraries focused on supporting SPIRE functionalities:

[![crates.io](https://img.shields.io/crates/v/spiffe.svg)](https://crates.io/crates/spiffe)
[![docs.rs](https://docs.rs/spiffe/badge.svg)](https://docs.rs/spiffe)
![CI](https://github.com/maxlambrecht/rust-spiffe/workflows/Continuous%20Integration/badge.svg)
[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://github.com/maxlambrecht/rust-spiffe/blob/main/LICENSE)
## [spiffe](./spiffe)

## Getting Started

Include `spiffe` in your `Cargo.toml` dependencies:

```toml
[dependencies]
spiffe = "0.3.1"
```

## Examples of Usage

### Creating a `WorkloadApiClient`

Create client using the endpoint socket path:

```rust
let mut client = WorkloadApiClient::new_from_path("unix:/tmp/spire-agent/public/api.sock").await?;
```

Or by using the `SPIFFE_ENDPOINT_SOCKET` environment variable:

```rust
let mut client = WorkloadApiClient::default().await?;
```

### Fetching X.509 Materials

Fetch the default X.509 SVID, a set of X.509 bundles, all X.509 materials, or watch for updates on the X.509 context and bundles.

```rust
// fetch the default X.509 SVID
let x509_svid: X509Svid = client.fetch_x509_svid().await?;

// fetch a set of X.509 bundles (X.509 public key authorities)
let x509_bundles: X509BundleSet = client.fetch_x509_bundles().await?;
The `spiffe` crate enables interaction with
the [SPIFFE Workload API](https://github.com/spiffe/spiffe/blob/main/standards/SPIFFE_Workload_API.md). It allows
fetching of X.509 and JWT SVIDs, bundles, and supports watch/stream updates. The types in the library are in compliance
with [SPIFFE standards](https://github.com/spiffe/spiffe/tree/main/standards). More about SPIFFE can be found
at [spiffe.io](https://spiffe.io/).

// fetch all the X.509 materials (SVIDs and bundles)
let x509_context: X509Context = client.fetch_x509_context().await?;
- [Read the README](./spiffe/README.md) for more information.

// get the X.509 chain of certificates from the SVID
let cert_chain: &Vec<Certificate> = x509_svid.cert_chain();
## [spire-api](./spire-api)

// get the private key from the SVID
let private_key: &PrivateKey = x509_svid.private_key();
The `spire-api` crate provides support for SPIRE specific APIs, including the Delegated Identity API.

// parse a SPIFFE trust domain
let trust_domain = TrustDomain::try_from("example.org")?;
- [Read the README](./spire-api/README.md) for more information.

// get the X.509 bundle associated to the trust domain
let x509_bundle: &X509Bundle = x509_bundles.get_bundle(&trust_domain)?;

// get the X.509 authorities (public keys) in the bundle
let x509_authorities: &Vec<Certificate> = x509_bundle.authorities();

// watch for updates on the X.509 context
let mut x509_context_stream = client.watch_x509_context_stream().await?;
while let Some(x509_context_update) = x509_context_stream.next().await {
match x509_context_update {
Ok(update) => {
// handle the updated X509Context
}
Err(e) => {
// handle the error
}
}
}

// watch for updates on the X.509 bundles
let mut x509_bundle_stream = client.watch_x509_bundles_stream().await?;
while let Some(x509_bundle_update) = x509_bundle_stream.next().await {
match x509_bundle_update {
Ok(update) => {
// handle the updated X509 bundle
}
Err(e) => {
// handle the error
}
}
}
```

### Fetching and Validating JWT Tokens and Bundles

Fetch JWT tokens, parse and validate them, fetch JWT bundles, or watch for updates on the JWT bundles.

```rust
// parse a SPIFFE ID to ask a token for
let spiffe_id = SpiffeId::try_from("spiffe://example.org/my-service")?;

// fetch a jwt token for the provided SPIFFE-ID and with the target audience `service1.com`
let jwt_token = client.fetch_jwt_token(&["audience1", "audience2"], Some(&spiffe_id)).await?;

// fetch the jwt token and parses it as a `JwtSvid`
let jwt_svid = client.fetch_jwt_svid(&["audience1", "audience2"], Some(&spiffe_id)).await?;

// fetch a set of jwt bundles (public keys for validating jwt token)
let jwt_bundles = client.fetch_jwt_bundles().await?;

// parse a SPIFFE trust domain
let trust_domain = TrustDomain::try_from("example.org")?;

// get the JWT bundle associated to the trust domain
let jwt_bundle: &JwtBundle = jwt_bundles.get_bundle(&trust_domain)?;

// get the JWT authorities (public keys) in the bundle
let jwt_authority: &JwtAuthority = jwt_bundle.find_jwt_authority("a_key_id")?;
## Getting Started

// parse a `JwtSvid` validating the token signature with a JWT bundle source.
let validated_jwt_svid = JwtSvid::parse_and_validate(&jwt_token, &jwt_bundles_set, &["service1.com"])?;
Follow the links above to the individual README files for detailed information on how to use each library.

// watch for updates on the JWT bundles
let mut jwt_bundle_stream = client.watch_jwt_bundles_stream().await?;
while let Some(jwt_bundle_update) = jwt_bundle_stream.next().await {
match jwt_bundle_update {
Ok(update) => {
// handle the updated JWT bundle
}
Err(e) => {
// handle the error
}
}
}
```
## License

For more detailed examples and additional features, refer to the [documentation](https://docs.rs/spiffe).
This project is licensed under [LICENSE NAME](./LICENSE).
55 changes: 55 additions & 0 deletions RELEASING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Releasing Crates

Follow these steps to create a new release for a specific crate in the repository.

## 1. Prepare the Release

- Determine the crate you are releasing and the new version number.
- Update the crate's `Cargo.toml` file with the new version number on a dedicated branch.
- Update the CHANGELOG.md file with detailed notes about the new release. Include any new features, bug fixes, and other
relevant information.
- Update any relevant documentation, including README files and any public-facing documents related to the crate.

## 2. Create a Pull Request (PR) for Preparing the Release

- Push the branch and create a pull request to merge the changes into the main branch.
- Include the changes to the `Cargo.toml`, CHANGELOG.md, and documentation files in the PR.
- Engage the maintainers for a thorough review of the changes.

## 3. Merge the PR

- Once the PR is approved, merge it into the main branch.

## 4. Create the Release Branch

- Checkout the main branch.
- Create a new branch for the release, named with the pattern `release/CRATE-NAME-VERSION`.

For example:
```sh
git checkout -b release/spiffe-v0.3.2
```

## 5. Create a Git Tag

- Create a Git tag for the new release, using the same pattern `CRATE-NAME-VERSION`.

For example:
```sh
git tag spiffe-v0.3.2
```

- Push the tag and the branch to the repository.

## 6. Publish the Crate

For example:
```sh
cargo publish --manifest-path spiffe/Cargo.toml
```

## 7 Create a GitHub Release

Navigate to the "Releases" section in the repository on GitHub.
Draft a new release using the tag created earlier, and include the notes from the CHANGELOG.md.
Publish the release.
32 changes: 32 additions & 0 deletions scripts/agent.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
agent {
data_dir = "./data/agent"
log_level = "DEBUG"
trust_domain = "example.org"
server_address = "localhost"
server_port = 8081

# Insecure bootstrap is NOT appropriate for production use but is ok for
# simple testing/evaluation purposes.
insecure_bootstrap = true

admin_socket_path = "$STRIPPED_SPIRE_ADMIN_ENDPOINT_SOCKET"
authorized_delegates = [
"spiffe://example.org/myservice",
]
}

plugins {
KeyManager "disk" {
plugin_data {
directory = "./data/agent"
}
}

NodeAttestor "join_token" {
plugin_data {}
}

WorkloadAttestor "unix" {
plugin_data {}
}
}