Supply Chain Security Gateway
A reference architecture and proof of concept implementation of a supply chain security gateway with the goal of enforcing sane security policies to an organization’s consumption of 3rd party software (dependencies) in its own products.
TL;DR
Ensure git submodules are updated locally
git submodule update --init --recursive
Initialize keys and certificates for mTLS
sh bootstrap.sh
This will generate root certificate, per service certificates in
pki/
.
TLS SAN must be correctly set in the generated certificate for the mTLS to work correctly. Verify using:
openssl x509 -noout -text \
-in ./pki/nats-server/server.crt | grep "DNS:nats-server"
Start the services using docker-compose
docker-compose up -d
Verify all the services are active
docker-compose ps
Use the gateway using a demo-client
cd demo-clients/java-gradle && ./gradlew assemble --refresh-dependencies
At this point, you should see logs generated by gateway and the policy decision service and multiple artefacts that are violating configured policy are blocked by the gateway
docker-compose logs envoy
docker-compose logs pdp
The gradle
build should fail with an error message indicating a dependency was blocked by the gateway.
> Could not resolve all files for configuration ':app:compileClasspath'.
> Could not resolve org.apache.logging.log4j:log4j:2.16.0.
Required by:
project :app
> Could not resolve org.apache.logging.log4j:log4j:2.16.0.
> Could not get resource 'http://localhost:10000/maven2/org/apache/logging/log4j/log4j/2.16.0/log4j-2.16.0.pom'.
> Could not GET 'http://localhost:10000/maven2/org/apache/logging/log4j/log4j/2.16.0/log4j-2.16.0.pom'. Received status code 403 from server: Forbidden
Refer to
policies/example.rego
for the policy that blocked this artefact
Edit config/global.yml
and set pdp.monitor_mode=true
to enable only monitoring and disable policy enforcement. Restart the containers for the changes to take effect.
docker-compose up --force-recreate --remove-orphans --build -d
Run the build again to see it compile successfully.
cd demo-clients/java-gradle && ./gradlew build --refresh-dependencies
Architecture
Data Plane Flow
Usage
If you are developing on any of the service and want to force re-create the containers with updated image:
docker-compose up --force-recreate --remove-orphans --build -d
Authentication
There are two authentication points:
- Ingress
- Egress
Ingress authentication is for incoming requests to the gateway and can be used to identify who is accessing the gateway.
Egress authentication is for upstream repositories, especially the ones that need authentication e.g. CodeArtifact, JFrog, Nexus etc.
Ingress Authentication
Basic Authentication
Use htpasswd
to add users:
htpasswd -nbB user1 password1 >> ./config/config/gateway-auth-basic
Enable authentication for upstream in config/global.yml
Development
PDP Development
Build and run the PDP using:
cd services && make
GLOBAL_CONFIG_PATH=../config/global.yml PDP_POLICY_PATH=../policies ./out/pdp-server
PDP listens on 0.0.0.0:9000
. To use the host instance of PDP, edit config/envoy.yml
and set the address of the ExtAuthZ
plugin to your host network address.
Policy Development
Policies are written in Rego and evaluated with Open Policy Agent
To run policy test cases:
cd policies && make test
- Refer to
policies/example.rego
for policy example - Policies are load from
./policies
directory
Tap Development
The Tap Service is integrated as a Envoy ExtProc filter. This means, it has greater control over Envoy’s request processing life-cycle and can make changes if required.
Currently, it is used for publishing events for data collection only but in future may be extended to support other use-cases. Tap service internally implements a handler chain to delegate an Envoy event to its internal handlers. Example:
tapService, err := tap.NewTapService(config, []tap.TapHandlerRegistration{
tap.NewTapEventPublisherRegistration(),
})
To build and use from host:
cd services && make
GLOBAL_CONFIG_PATH=../config/global.yml ./out/tap-server
To use Tap service from host, edit
envoy.yml
and change address ofext-proc-tap
cluster.
Debug NATS Messaging
Start a docker container with nats
client
docker run --rm -it \
--network supply-chain-security-gateway_default \
-v `pwd`:/workspace \
synadia/nats-box
Subscribe to a subject and receive messages
GODEBUG=x509ignoreCN=0 nats sub \
--tlscert=/workspace/pki/tap/server.crt \
--tlskey=/workspace/pki/tap/server.key \
--tlsca=/workspace/pki/root.crt \
--server=tls://nats-server:4222 \
com.msg.event.upstream.request
Contribution
Look at Github issues