Skip to content

Commit

Permalink
Merge pull request #46 from maxlambrecht/spire-api
Browse files Browse the repository at this point in the history
* Refactor repository: new `spiffe` folder, new `spire-api` crate, and `spire-api-sdk` submodule (#42)

Signed-off-by: Max Lambrecht <maxlambrecht@gmail.com>

* Add delegated identity API support to spire-api package (#43)

Signed-off-by: Eitan Yarmush <eitan.yarmush@solo.io>

* Refactoring `spiffe` crate: Introducing `spiffe-types` and `workload-api` features (#44)

Signed-off-by: Max Lambrecht <maxlambrecht@gmail.com>

* Add Releasing Process Documentation for Crates (#45)

Signed-off-by: Max Lambrecht <maxlambrecht@gmail.com>

---------

Signed-off-by: Max Lambrecht <maxlambrecht@gmail.com>
Co-authored-by: Eitan Yarmush <eitan.yarmush@solo.io>
  • Loading branch information
maxlambrecht and EItanya committed Aug 21, 2023
2 parents 25a44c7 + 3c048f8 commit 657a872
Show file tree
Hide file tree
Showing 67 changed files with 2,254 additions and 361 deletions.
6 changes: 5 additions & 1 deletion .github/dependabot.yml
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
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
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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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 {}
}
}

0 comments on commit 657a872

Please sign in to comment.