SPIRE Software Statements Plugin
July 25, 2025 · View on GitHub
A SPIRE CredentialComposer plugin that adds software statement claims (jwks_url and client_auth) to JWT SVIDs for enhanced OAuth 2.0 and OpenID Connect integration.
Overview
This external plugin extends SPIRE's JWT SVID capabilities by automatically adding standardized OAuth 2.0 Dynamic Client Registration (RFC 7591) claims to all issued JWT SVIDs. These claims enable better integration with OAuth 2.0 authorization servers and API gateways that require software statement information.
Added Claims
jwks_url: URL to the JSON Web Key Set for JWT signature verificationclient_auth: Client authentication method- Custom claims: Additional configurable claims for your specific use case
client_auth claim can be one of:
client-secret client_secret_basic/client_secret_post Client secret authentication client-jwt private_key_jwt JWT Bearer - JWT signed with client's private key client-secret-jwt client_secret_jwt JWT signed with client secret client-x509 tls_client_auth X.509 certificate authentication client-spiffe-jwt (custom) Your SPIFFE JWT authentication
Features
- ✅ External Plugin: No need to modify SPIRE core - dynamic loading
- ✅ Production Ready: Comprehensive error handling and logging
- ✅ Configurable: Support for environment variables and external config files
- ✅ Secure: HTTPS URL validation and input sanitization
- ✅ Cross-Platform: Builds for Linux, macOS, Windows (amd64/arm64)
- ✅ Well Tested: Comprehensive unit test coverage
- ✅ Easy Installation: Automated build and installation scripts
Prerequisites
- SPIRE Server: Version 1.8.0 or later
- Go: Version 1.21 or later (for building from source)
- Operating System: Linux, macOS, or Windows
- Architecture: amd64 or arm64
Quick Start
1. Build the Plugin
# Clone or navigate to the plugin directory
cd spire-software-statements
# Build for your current platform
make build
# Or build for all platforms
make build-all
2. Install the Plugin
# Install to default location (/opt/spire/plugins)
sudo make install
# Or use the installation script with custom options
./scripts/install.sh --generate-config
3. Configure SPIRE Server
Add the plugin to your SPIRE server configuration:
plugins {
CredentialComposer "software_statements" {
plugin_cmd = "/opt/spire/plugins/spire-software-statements"
plugin_checksum = "your_plugin_checksum_here"
plugin_data = {
jwks_url = "https://auth.example.org/.well-known/jwks.json"
client_auth = "client_secret_basic"
}
}
}
4. Restart SPIRE Server
sudo systemctl restart spire-server
5. Verify Installation
Check that the plugin is loaded:
# Check SPIRE server logs
sudo journalctl -u spire-server -f | grep software_statements
# Test JWT SVID generation
spire-agent api fetch jwt -audience "https://api.example.org"
Configuration
Basic Configuration
# Required: JWKS URL for JWT signature verification
jwks_url = "https://auth.example.org/.well-known/jwks.json"
# Required: OAuth 2.0 client authentication method
client_auth = "client_secret_basic"
Advanced Configuration
jwks_url = "https://auth.example.org/.well-known/jwks.json"
client_auth = "private_key_jwt"
# Optional: Additional claims
additional_claims = {
"scope" = "spiffe:read spiffe:write"
"software_statement" = "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9..."
"client_metadata_uri" = "https://client.example.org/metadata"
"organization" = "Example Corp"
"environment" = "production"
}
Environment Variables
Use environment variables for dynamic configuration:
jwks_url = "${JWKS_ENDPOINT_URL}"
client_auth = "${CLIENT_AUTH_METHOD}"
additional_claims = {
"organization" = "${ORG_NAME}"
"environment" = "${DEPLOYMENT_ENV}"
}
External Configuration File
Reference an external configuration file:
CredentialComposer "software_statements" {
plugin_cmd = "/opt/spire/plugins/spire-software-statements"
plugin_checksum = "your_checksum"
plugin_data_file = "/etc/spire/plugins/software-statements.hcl"
}
Configuration Options
| Option | Type | Required | Description |
|---|---|---|---|
jwks_url | string | Yes | HTTPS URL to JSON Web Key Set |
client_auth | string | Yes | Client authentication method |
additional_claims | map | No | Additional claims to add to JWT SVIDs |
Valid Client Authentication Methods
client_secret_basic- HTTP Basic authenticationclient_secret_post- POST body parametersclient_secret_jwt- JWT assertion with shared secretprivate_key_jwt- JWT assertion with private keynone- No authentication
Building
Local Build
# Build for current platform
make build
# Build with specific platform
make build GOOS=linux GOARCH=amd64
# Run tests
make test
# Build and run tests
make check
Cross-Platform Build
# Build for all supported platforms
make build-all
# Generate checksums
make checksums
# Create release packages
make release
Docker Build
# Build Docker image
make docker
# Run plugin in container
make docker-run
Installation Methods
Method 1: Makefile (Recommended)
# Install with default options
sudo make install
# Install to custom directory
sudo make install PLUGIN_DIR=/custom/path
# Uninstall
sudo make uninstall
Method 2: Installation Script
# Interactive installation with config generation
./scripts/install.sh --generate-config
# Dry run to see what would be installed
./scripts/install.sh --dry-run
# Install to custom location
./scripts/install.sh --plugin-dir /custom/path
# Force overwrite existing installation
./scripts/install.sh --force
Method 3: Manual Installation
# Copy binary
sudo cp build/spire-software-statements /opt/spire/plugins/
# Generate checksum
sha256sum /opt/spire/plugins/spire-software-statements
# Update SPIRE configuration with checksum
# Restart SPIRE server
Usage Examples
Example 1: Basic OAuth 2.0 Integration
CredentialComposer "software_statements" {
plugin_cmd = "/opt/spire/plugins/spire-software-statements"
plugin_checksum = "abc123..."
plugin_data = {
jwks_url = "https://auth.company.com/.well-known/jwks.json"
client_auth = "client_secret_basic"
}
}
Resulting JWT Claims:
{
"sub": "spiffe://company.com/service/api",
"aud": ["https://api.company.com"],
"iat": 1709334000,
"exp": 1709337600,
"jwks_url": "https://auth.company.com/.well-known/jwks.json",
"client_auth": "client_secret_basic"
}
Example 2: Enhanced Software Statements
CredentialComposer "software_statements" {
plugin_cmd = "/opt/spire/plugins/spire-software-statements"
plugin_checksum = "abc123..."
plugin_data = {
jwks_url = "https://auth.company.com/.well-known/jwks.json"
client_auth = "private_key_jwt"
additional_claims = {
"software_statement" = "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9..."
"scope" = "api:read api:write"
"software_version" = "1.2.0"
"certification" = "FAPI-R"
}
}
}
Example 3: Environment-Based Configuration
# Set environment variables
export JWKS_ENDPOINT_URL="https://auth.staging.company.com/.well-known/jwks.json"
export CLIENT_AUTH_METHOD="private_key_jwt"
export ORG_NAME="Company Inc"
export ENVIRONMENT="staging"
CredentialComposer "software_statements" {
plugin_cmd = "/opt/spire/plugins/spire-software-statements"
plugin_checksum = "abc123..."
plugin_data = {
jwks_url = "${JWKS_ENDPOINT_URL}"
client_auth = "${CLIENT_AUTH_METHOD}"
additional_claims = {
"organization" = "${ORG_NAME}"
"environment" = "${ENVIRONMENT}"
}
}
}
Development
Development Environment
# Set up development tools
make dev-setup
# Run tests with coverage
make test
# Format code
make format
# Run linters
make lint
# Full check (format + lint + test)
make check
Docker Development
# Start development environment
cd examples
docker-compose up -d
# View logs
docker-compose logs -f spire-server
# Test JWT generation
docker-compose exec sample-workload \
spire-agent api fetch jwt -audience "https://api.example.org"
# Clean up
docker-compose down -v
Testing
# Run unit tests
go test ./...
# Run tests with coverage
go test -cover ./...
# Run integration tests (requires Docker)
cd examples && docker-compose up -d
# Wait for services to be healthy
# Run your integration tests
docker-compose down -v
Troubleshooting
Plugin Not Loading
Symptoms:
- SPIRE server fails to start
- Error messages about plugin loading
Solutions:
- Verify plugin checksum matches the binary
- Check plugin path is correct and file is executable
- Ensure SPIRE server has permission to read the plugin file
# Regenerate checksum
./scripts/checksum.sh show /opt/spire/plugins/spire-software-statements
# Check permissions
ls -la /opt/spire/plugins/spire-software-statements
# Test plugin manually
/opt/spire/plugins/spire-software-statements --help
Configuration Validation Errors
Symptoms:
- Plugin loads but SPIRE server reports configuration errors
Solutions:
- Validate JWKS URL is HTTPS and accessible
- Check client authentication method is valid
- Verify HCL syntax
# Validate configuration
./scripts/install.sh --dry-run
# Test JWKS URL accessibility
curl -s https://your-domain.com/.well-known/jwks.json | jq
JWT Claims Not Appearing
Symptoms:
- JWT SVIDs are generated but don't contain expected claims
Solutions:
- Check SPIRE server logs for plugin errors
- Verify plugin is configured for CredentialComposer
- Ensure JWT SVID generation (not X.509)
# Check plugin logs
journalctl -u spire-server | grep software_statements
# Test JWT generation specifically
spire-agent api fetch jwt -audience "test" -socketPath /tmp/spire-agent/public/api.sock
Performance Issues
Symptoms:
- Slow JWT SVID generation
- High memory usage
Solutions:
- Minimize additional_claims
- Use environment variables instead of large inline values
- Monitor plugin resource usage
Common Error Messages
| Error | Cause | Solution |
|---|---|---|
plugin not configured | Plugin configuration missing | Check SPIRE server config |
invalid jwks_url: JWKS URL must use HTTPS | HTTP URL provided | Use HTTPS URL |
invalid client_auth method | Unsupported auth method | Use supported method |
failed to parse configuration | Invalid HCL syntax | Validate HCL configuration |
Security Considerations
Plugin Security
- Checksum Verification: Always use plugin checksums in production
- File Permissions: Ensure plugin binary is not writable by non-root users
- HTTPS Only: JWKS URLs must use HTTPS
- Input Validation: All configuration inputs are validated
JWT Security
- Key Management: Ensure JWKS endpoints are properly secured
- Token Validation: Verify JWT signatures using the provided JWKS URL
- Claim Validation: Validate all claims, including custom ones
- Audience Restriction: Use specific audiences for different services
Best Practices
- Use Environment Variables for sensitive configuration values
- Minimize Claims to reduce JWT size and attack surface
- Regular Updates of plugin and SPIRE versions
- Monitor Logs for security-related events
- Network Security for JWKS endpoint access
Performance
Benchmarks
The plugin adds minimal overhead to JWT SVID generation:
- Latency Impact: < 1ms additional processing time
- Memory Usage: < 10MB additional memory per plugin instance
- CPU Impact: Negligible CPU overhead
Optimization Tips
- Minimize Additional Claims: Each claim adds to JWT size
- Cache JWKS URLs: Use CDN or caching for JWKS endpoints
- Environment Variables: Faster than file-based configuration
- Resource Limits: Set appropriate container resource limits
Contributing
We welcome contributions! Please see the following guidelines:
Development Workflow
- Fork the repository
- Create a feature branch:
git checkout -b feature/new-feature - Make your changes
- Add tests for new functionality
- Run the test suite:
make check - Commit your changes:
git commit -am 'Add new feature' - Push to the branch:
git push origin feature/new-feature - Create a Pull Request
Code Standards
- Follow Go best practices and idioms
- Maintain test coverage above 80%
- Use meaningful commit messages
- Update documentation for new features
- Ensure all checks pass:
make check
Testing Requirements
- Unit tests for all new functions
- Integration tests for major features
- Error case testing
- Performance regression testing
License
This project is licensed under the Apache License 2.0 - see the LICENSE file for details.
Changelog
v1.0.0 (Initial Release)
- ✅ Basic JWT claim enhancement with
jwks_urlandclient_auth - ✅ Support for additional custom claims
- ✅ Environment variable configuration
- ✅ External configuration file support
- ✅ Cross-platform builds (Linux, macOS, Windows)
- ✅ Comprehensive test coverage
- ✅ Docker support and examples
- ✅ Installation and build automation
Support
Getting Help
- Documentation: Check this README and example configurations
- Issues: Report bugs and feature requests via GitHub Issues
- Discussions: Ask questions in GitHub Discussions
- SPIRE Community: Join the SPIRE Slack
Reporting Issues
When reporting issues, please include:
- Plugin version and build information
- SPIRE server version
- Operating system and architecture
- Complete error messages and logs
- Minimal reproduction configuration
- Steps to reproduce the issue
Feature Requests
We welcome feature requests! Please provide:
- Clear description of the desired functionality
- Use case and business justification
- Proposed implementation approach (if any)
- Backwards compatibility considerations
Made with ❤️ for the SPIFFE/SPIRE community