Giter VIP home page Giter VIP logo

chainloop-dev / chainloop Goto Github PK

View Code? Open in Web Editor NEW
314.0 8.0 22.0 21.03 MB

Chainloop is an Open Source evidence store for your Software Supply Chain attestations, SBOMs, VEX, SARIF, CSAF files, QA reports, and more.

Home Page: https://docs.chainloop.dev

License: Apache License 2.0

Makefile 0.48% Dockerfile 0.05% Go 97.44% Smarty 0.77% SQL 1.26%
compliance cyclonedx devsecops sbom sbom-distribution security spdx supply-chain-security metadata-platform sbom-discovery

chainloop's Introduction

Chainloop

OpenSSF Scorecard Go Report Card Test passing Chat on Discord License: Apache-2.0

Chainloop is under active development and you should expect breaking changes before the first stable release. If you are interested in contributing, please take a look at our contributor guide.

What is it?

Chainloop is an open-source Software Supply Chain control plane, a single source of truth for metadata and artifacts, plus a declarative attestation process.

With Chainloop, SecOps teams can declaratively state the pieces of evidence and artifact expectations for their organization’s CI/CD workflows. At the same time, they can rest assured that the metadata will reach the desired destination for storage and analysis, always meeting the latest standards and best practices.

On the other hand, developer teams do not need to become security experts. The attestation crafting tool will guide them with guardrails and a familiar developer experience.

To learn more about the project motivation please look at our documentation and see it in action in this video.

Getting started

See the getting started guide for detailed information on a) how to download and configure the Chainloop CLI and b) how to deploy Chainloop on your Kubernetes Cluster.

Command Line Interface (CLI) installation

Alternatively, you can download the CLI from the releases pages or build it from source.

To install the latest version for macOS, Linux or Windows (using WSL) just choose one of the following installation methods.

curl -sfL https://raw.githubusercontent.com/chainloop-dev/chainloop/main/docs/static/install.sh | bash -s

you can retrieve a specific version with

curl -sfL https://raw.githubusercontent.com/chainloop-dev/chainloop/main/docs/static/install.sh | bash -s -- --version v0.8.95

and customize the install path (default to /usr/local/bin)

curl -sfL https://raw.githubusercontent.com/chainloop-dev/chainloop/main/docs/static/install.sh | bash -s -- --path /my-path

if cosign is present in your system, in addition to the checksum check, a signature verification will be performed. This behavior can be enforced via the --force-verification flag.

curl -sfL https://raw.githubusercontent.com/chainloop-dev/chainloop/main/docs/static/install.sh | bash -s -- --force-verification

Deploy Chainloop (optional)

Downloading the CLI is everything you need to give Chainloop a try, since, by default, it points to a running instance of Chainloop.

You can also run your own Chainloop instance on your Kubernetes cluster by leveraging this Helm Chart.

Configure CLI (optional)

If you are running your own instance of the Control Plane. You can make the CLI point to your instance by using the chainloop config save command.

chainloop config save \
  --control-plane my-controlplane.acme.com \
  --artifact-cas cas.acme.com

Authentication

Authenticate to the Control Plane by running

$ chainloop auth login

Finishing the setup

Once you've been logged in, follow these instructions to learn how to set up your account.

How does it work?

Compliant Single Source of Truth

Craft and store attestation metadata and artifacts via a single integration point regardless of your CI/CD provider choice.

Chainloop Overview

The result is having a SLSA level 3 compliant single Source of truth for metadata, artifacts and attestations built on OSS standards such as Sigstore, in-toto, SLSA and OCI.

Chainloop also makes sure the crafting of artifacts and attestation follows best practices and meets the requirements declared in their associated Workflow Contract.

Declarative, contract-based attestation

One key aspect is that in Chainloop, CI/CD integrations are declared via Workflow Contracts.

A Workflow Contract gives operators full control over what kind of data (build info, materials) must be received as part of the attestation and the environment where these workflows must be executed at. This enables an easy, and maintainable, way of propagating and enforcing requirements downstream to your organization.

You can think of it as an API for your organization's Software Supply Chain that both parties, development and SecOps teams can use to interact effectively.

Chainloop Contracts

We meet you where you are with third-party integrations

Operators can set up third-party integrations such as Dependency-Track, or Guac for SBOM analysis or a storage backend such as an OCI registry, or cloud blob storage to place the received artifacts, pieces of evidence and attestation metadata.

Chainloop Overview

Ops can mix and match with different integrations while not requiring developers to make any changes on their side!

To learn more and to find the list of available integrations, check our integrations page.

Role-tailored experience

Chainloop makes sure to clearly define the responsibilities, experience and functional scope of the two main personas, Security/Operation (SecOps) and Development/Application teams.

SecOps are the ones in charge of defining the Workflow Contracts, setting up third-party integrations, or having access to the control plane where all the Software Supply Chain Security bells and whistles are exposed.

Development teams on the other hand, just need to integrate Chainloop's jargon-free crafting tool and follow the steps via a familiar DevExp to make sure they comply with the Workflow Contract defined by the SecOps team. No need to learn in-toto, signing, SLSA, OCI, APIs, nada :)

Supported Pieces of Evidence / Materials

Chainloop supports the collection of the following pieces of evidence types:

During the attestation process, these pieces of evidence will get uploaded to the Content Addressable Storage (if applicable) and referenced in a SLSA attestation.

Documentation

To learn more, please visit the Chainloop project's documentation website, https://docs.chainloop.dev where you will find a getting started guide, FAQ, examples, and more.

Community / Discussion / Support

Chainloop is developed in the open and is constantly improved by our users, contributors and maintainers. Got a question, comment, or idea? Please don't hesitate to reach out via:

Contributing

Want to get involved? Contributions are welcome.

If you are ready to jump in and test, add code, or help with documentation, please follow the instructions on our Contribution page. At all times, follow our Code of Conduct.

See the issue tracker if you're unsure where to start, especially the Good first issue label.

Changelog

Take a look at the list of releases to stay tuned for the latest features and changes.

License

Chainloop is released under the Apache License, Version 2.0. Please see the LICENSE file for more information.

chainloop's People

Contributors

buccarel avatar cristiangauma avatar danlishka avatar dependabot[bot] avatar fgallina avatar github-actions[bot] avatar gr0 avatar javirln avatar jiparis avatar migmartri avatar miguelaeh avatar sedan07 avatar shykes avatar step-security-bot avatar wojciechka avatar zaibon avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

chainloop's Issues

Okteto-based development environment

Currently, for development we leverage a combination of native execution (go run) and docker compose for its dependencies. We now have a Helm Chart deployment template that not incidentally includes a development mode

We might be able to use this Chart as a base for an Okteto development environment

The experience should be at least as seamless as deploying the Helm Chart in development mode (require only to point to an existing OIDC provider). I am not saying to match the actual development env (not requiring anything, DEX is bundled and run locally) we have because I expect The OIDC provider (DEX) setup to be tricky (due to domain changes). If we manage to do it, even better!

Ansible runner support

We'd like to explore what creating attestations from an ansible playbook could look like and hence adding it to the list of supported runner types.

This task is about

  • Research and describe what using Chainloop with Ansible could look like
  • Add Ansible as supported runner, similar to #88

JUnit XML material type

It would be useful to add JUnit XML report format to Chainloop as first class citizen material type.

This will allow developer teams to attest their test results as part of their attestation as well as operators to enable custom destination endpoints and analysis integrations in the future.

https://www.ibm.com/docs/en/developer-for-zos/14.1?topic=formats-junit-xml-format

This requires

CLI: improve UX on attestation downloading

When an user retrieves the information of an attestation, i.e chainloop wf run describe --id [ID], the prompt takes up to a couple of seconds due to the fact that in the backend, the attestation is retrieved from an OCI registry.

describe

This makes the user experience sub-optimal, we should probably tell the user that the system is working and we are waiting for the attestation.

We have different feedback options

I'd personally check if 2 is a good fit since we already use it.

Webhook based generic fan-out integration

Operators can setup third-party integrations to send materials or attestations once received by the controlplane. These integrations in general are meant to be off-the-shelf i.e dependency-track, guacsec/guac, OCI registry, but in some cases you might want to actuate on a custom endpoint.

This is useful if you've built a custom backend or simply as an escape hatch while your desired integration is not available yet.

This task is about designing and implementing a fan-out integration that could send attestations to a provided webhook URL.

replace inline secret_prefix option

Chainloop supports two backends to store secrets, vault and aws secrets manager. The choice of one vs the other can be done via config flags i.e

oneof backend {
AWSSecretManager aws_secret_manager = 1;
Vault vault = 2;
}

One of the settings is the secret prefix

string secret_prefix = 3;

This option is common in two backends, in other words, there is no need to be configured inside each backend payload but instead on the top level proto message.

This issue is about deprecating the inline secret_prefix and add a new top one under .credentials message.

Note that this change affects to both the controlplane and the CAS

Integrate with .docker/config or OIDC provider setups

The current flow requires an explicit username password pair.

I believe security could be enhanced with JIT credentials with short-expiry times.
The easiest would be to leverage existing local .docker configuration or environment variables for OIDC setups like IRSSA and WorkloadIdentity.

Thoughts? :)

docs: add per-project documentation

Currently the documentation for the control-plane, CAS and CLI is missing.

This task is about filling out their READMEs with some runbooks

Issue upgrading grpc to `v1.55.0`

If we update google.golang.org/grpc to v1.55.0 go mod tidy will fail

go mod tidy                             
go: finding module for package google.golang.org/grpc/test/grpc_testing
github.com/chainloop-dev/chainloop/app/artifact-cas/internal/server imports
	github.com/go-kratos/kratos/v2/errors tested by
	github.com/go-kratos/kratos/v2/errors.test imports
	google.golang.org/grpc/test/grpc_testing: module google.golang.org/grpc@latest found (v1.55.0), but does not contain package google.golang.org/grpc/test/grpc_testing

This is due that kratos is not compatible with gRPC v1.55.0 yet go-kratos/kratos#2832 and the fix will be in the next release.

This issue is about both upgrading grpc and kratos once the release is available 2.6.2+ https://github.com/go-kratos/kratos/releases

NOTE: cloud.google.com/go/secretmanager has also been kept back to v1.10.0 since 1.10.1 requires [email protected]. We should consider bumping this library too.

Deployment templates

Currently, this repository does not include templates to deploy Chainloop in Kubernetes. This task is about adding, packaging and publishing a Helm Chart that does so.

We need to decide what level of pre-configuration we want it to have. For example, our development environment works out of the box because we added Vault, PostgreSQL and Dex for OIDC. Should we do something similar in our Chart so the default settings works in such a way that you can have an out of the box experience?

Regardless of that decision, what we need to offer are enough configuration nobs to connect to external services, i.e RDS/CloudSQL for Database, AWS secret manager or Auth0 for example.

Keyless Signing / Verification using Sigstore

Currently, DSSE envelopes generated are signed and verified via a asymmetric cosign key.

Signing and pushing in the CI

chainloop attestation push --key [COSIGN PRIVATE KEY]

Verification on the operator side

chainloop workflow run describe --verify --key [COSIGN PUBLIC KEY]

We'd like to explore keyless signing and verification leveraging the Sigstore Suite (Fulcio and Rekor)

From top of my mind this could be deploying an instance of fulcio and rekor next to Chainloop per tenant that will be used to:

Signing

  • Get temporary signing key (look into workload identity too) from fulcio.
  • Sign DSSE envelope
  • Push it to the rekor instance

Verification

  • Retrieve the public key from the rekor transparent log and use it for verification.

Ideally, once we setup keyless signing, the need to setup a private key and passphrase in the CI will be removed simplifying the setup even more.

This task starts by writing a design document describing the details.

Some useful links

Attestation materials server side verification

IMPORTANT: This will be potentially superseded by #122

During the attestation process, the CLI will make sure that before crafting, signing and pushing the in-toto attestation to the control-plane, it meets the requirements of the associated workflow contract.

For example, this is an in-progress attestation that requires three materials, two of them have not been provided yet.

$ chainloop att status
┌───────────────────┬──────────────────────────────────────┐
│ Initialized At    │ 15 Mar 23 11:48 UTC                  │
├───────────────────┼──────────────────────────────────────┤
│ Workflow          │ 37022b2f-34c3-4f47-9fd7-514b4a7baaad │
│ Name              │ build-and-release                    │

┌───────────────────────────────────────────────────────────┐
│ Materials                                                 │
├────────┬─────────────────────┬─────┬──────────┬───────────┤
│ NAME   │ TYPE                │ SET │ REQUIRED │ IS OUTPUT │
├────────┼─────────────────────┼─────┼──────────┼───────────┤
│ image  │ CONTAINER_IMAGE     │ Yes │ Yes      │ x         │
│ binary │ ARTIFACT            │ No  │ Yes      │           │
│ sbom   │ SBOM_CYCLONEDX_JSON │ No  │ Yes      │           │
└────────┴─────────────────────┴─────┴──────────┴───────────┘

When you try to push it, the CLI will complain

$ chainloop att push
ERR some materials have not been crafted yet: binary, sbom

A similar server-side validation is not been performed in the server side.

This task is about implementing server side validations on the control plane API Attestation.Store method

rpc Store (AttestationServiceStoreRequest) returns (AttestationServiceStoreResponse);

This validation must

  • Unpack the received DSSE envelope and extract the attestation,
  • Make sure that the attestation is for the workflow run we receive as part of the robot-account token
  • Verify it's content against the contract revision associated with the workflow run.

For a future task, we should look into verifying the DSSE payload by checking the signature, but to do that we might need to also sign the envelope with a key known by the control plane. Currently the payload is signed by a key provided by the user.

[fan-out integration] Record triggered integrations and results

Operators can attach integrations to their workflows, this means that these integrations will get triggered when an attestation is received.

The problem with the current implementation is that there is not actual paper trail of the 1) execution of the integration and 2) its result.

We should store in the DB a new entity, i.e integrationEvents associated with workflowRun that will contain the different immutable events of when an integration was queued, in-progress or finished with or without error and an optional result struct.

This will allow us to show such events in chronological order, enable async processing and events replay in the future and so on.

Recording the result is a potential prerequisite for #122

See #39 for more information about the global effort on improving integrations firing logic.

Replace pull-request -> discord PR post mechanism

Currently we are leveraging make.com to send Pull requests notifications to discord

This method has some drawbacks

  • It works on intervals of 15 minutes
  • The free tier is so limited that pretty much we'd need to upgrade to a paid plan due to the number of operations that it runs.
  • We have a third party with access to this repository PRs

I've asked around and it seems that some people are leveraging instead a push method such as this action

This task is about implementing this or a similar action in our GitHub Action CI process. We should probably start only on new issues and pull-requests

logger regression existing in attestation service

During the update to variadic options in NewAttestationService() a regression was added that made the logger not to be available making the go-routine to fail.

"level":"info","ts":1678228411.2617261,"kind":"server","component":"grpc","operation":"/controlplane.v1.AttestationService/Store","args":"***","code":0,"reason":"","stack":"","latency":0.006055486}
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x1756b90]

goroutine 32545 [running]:
github.com/go-kratos/kratos/v2/log.(*Helper).Infow(...)
        /home/runner/go/pkg/mod/github.com/go-kratos/kratos/[email protected]/log/helper.go:81
github.com/chainloop-dev/chainloop/app/controlplane/internal/service.uploadSBOMsToDependencyTrack(0xc00109d7c0)
  • Make sure the logger is initialized
  • Add a default logger for the parent struct to prevent future cases

update installation script to use github releases

Currently curl -sfL https://chainloop.dev/install.sh | bash -s leverages

  • The control plane infoz endpoint to find the latest version which then gets retrieved from Google Cloud object storage.

Now that the binaries are public, we should update the script to use Github releases instead.

As a second step, we could also host the install script in this repo as well.

Improve CLI feedback on configuration change

Currently, the CLI allows configuration overrides via the config save

Persist the current settings to the config file

Usage:
  chainloop config save [flags]

Examples:
chainloop config save --control-plane localhost:1234 --artifact-cas localhost:1235

The main issue is that when the command finishes successfully, no feedback is sent back to the user.

Ideally we should indicate that the changes have been persisted, in which location and show the current values, similar to config view

chainloop config view   
Config file: /home/migmartri/.config/chainloop/config.toml
control-plane: api.cp.chainloop.dev:443
artifact-cas: api.cas.chainloop.dev:443

Decouple user/robot-account JWTs passphrases

Currently, the control plane generates three JSON Web Tokens for different purposes.

a) User JWT

This one is generated once an user authenticate with the control plane, i.e chainloop auth login, it will be minted once the authentication with the upstream OIDC identity provider is completed. This token is valid for 24 hours and it's what the CLI uses to authenticate requests (stored at /.config/chainloop/config.toml).

b) Robot Account JWT

This is along non-expiring token (but revocable) meant to be used as part of the integration with the CI.

chainloop wf robot-account ...

c) CAS temporary download/upload JWT

The CLI, when it needs to perform an operation with the artifact-CAS, asks the control plane for short-living credentials to do so.

This token is signed with a private key in the control plane and verified with a public key in the CAS, see https://github.com/chainloop-dev/chainloop/tree/main/app/artifact-cas#authnauthz

On the other hand, both the User JWT (a) and the robot-account token (b) use a HS256 symmetric passphrase for both signing and verifying, in fact they use the same key, this task is about making sure that each JWT builder uses their own passphrase.

NOTE: Using a different signing method, i.e asymmetric, JWKS is out of the scope of this task, in my opinion can should tackle it in a follow up task.

Currently, the passphrase that both JWT builders use is defined here

string generated_jws_hmac_secret = 2;

We should split that in two different configuration options

NOTE: before this task I'd take a look at #23 since configuration options might change.

  • Deprecate current configuration key and add two new ones that clearly state what's their target audience.
  • Update GRPC middlewares and JWT builders

CLI: rewrite defaults

Currently, the Chainloop CLI has "baked" some defaults for the ControlPlane and Artifact proxy API endpoints.

chainloop 
Chainloop Command Line Interface
...
Flags:
      --artifact-cas string    URL for the Artifacts Content Addressable Storage (CAS) (default "api.cas.chainloop.dev:443")
      --control-plane string   URL for the Control Plane API (default "api.cp.chainloop.dev:443")
...

These options can be overridden on demand by running chainloop config save ... which then stores such overrides in a local config file.

This task is instead about being able to override the defaults so the CLI, once compiled it's ready to use pointing to any custom Chainloop instance.

  • Offer optional build options to override both flags
  • Document how to compile the CLI binary with custom options

review need of redirect_url_scheme

There is a custom option set in the controlplane called redirect_url_scheme that we should double check if it can be inferred automatically instead.

This option is used to indicate the oidc callback what schema to use, and it's configured in the config files under the auth.oidc section. This option is yet another nob that will need to be tweaked by the user during deployment and we should look into simplifying it.

Jenkins runner support

Chainloop has support for CI/CD runners, this task is about adding Jenkins (and JenkinsX) to the list of supported ones.

On the technical side it meens implementing this interface

type supportedRunner interface {
// Whether the attestation is happening in this environment
CheckEnv() bool
// List the env variables registered
ListEnvVars() []string
// Return the list of env vars associated with this runner already resolved
ResolveEnvVars() map[string]string
String() string
// uri to the running job/workload
RunURI() string
}

which will require you to inspect and figure out 1) how to know that you are in that runner, 2) what env variables you care about for the tool to auto-discover and 3) how to create a link to the workflow.

Additionally you'll need to update the contract definition to support this new runner type

enum RunnerType {
RUNNER_TYPE_UNSPECIFIED = 0;
GITHUB_ACTION = 1;
GITLAB_PIPELINE = 2;
}

Create first robot-account during workflow creation

Usuallym the steps required to create and use a workflow are

Create a workflow chainloop wf create

$ chainloop wf create --name test --project test
┌──────────────────────────────────────┬──────┬─────────┬─────────────────────┬────────┬─────────────────┐
│ ID                                   │ NAME │ PROJECT │ CREATED AT          │ RUNNER │ LAST RUN STATUS │
├──────────────────────────────────────┼──────┼─────────┼─────────────────────┼────────┼─────────────────┤
│ 71de5436-ef9e-4f27-99c6-a67826f7c0a5 │ testtest    │ 24 Apr 23 14:09 UTC │        │                 │
└──────────────────────────────────────┴──────┴─────────┴─────────────────────┴────────┴─────────────────┘

Create a robot account pointing to that workflow ID

$ chainloop wf robot-account create --workflow 71de5436-ef9e-4f27-99c6-a67826f7c0a5
┌──────────────────────────────────────┬──────┬──────────────────────────────────────┬─────────────────────┬────────────┐
│ ID                                   │ NAME │ WORKFLOW ID                          │ CREATED AT          │ REVOKED AT │
├──────────────────────────────────────┼──────┼──────────────────────────────────────┼─────────────────────┼────────────┤
│ f1f5cc7d-c7eb-4e84-ae45-3b1437d062a6 │      │ 71de5436-ef9e-4f27-99c6-a67826f7c0a5 │ 24 Apr 23 14:09 UTC │            │
└──────────────────────────────────────┴──────┴──────────────────────────────────────┴─────────────────────┴────────────┘

Save the following token since it will not printed again: 

 eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.REDACTED-I

This task is about by default, create a token as well, unless an optional flag is set that prevents that, i.e --skip-robot-account-create

We need to decide where to implement this, server-side or client-side. My gut tells me, based on the limited information we have, that there is no enough data to corroborate that such a change should be implemented by default in the server. So I am leaning towards a client side implementation of it (although automatic contract creation happens server side)

review CAS memory handling

The CAS of the running instance of Chainloop has been reaching the limit of 512mi and being killed by the scheduler making some release jobs fail.

Memory

We have increased the memory limit to 1GB but we should look into the memory handling of uploads to make sure there is proper handling and no leaks.

[fan-out integration] add resiliency to firing mechanism

Chainloop, currently has a mechanism to send attestation and artifact metadata to third party-integrations such an OCI registry (attestation) and Dependency-Track (CycloneDX SBOM).

225039624-72816cc9-8247-426e-8b94-622c469d93d9

It's implementation today happens in the service layer and has some drawbacks due to it's naive initial implementation using a go-routine

  • It does not have delivery guarantees.
  • It happens in memory so container restarts or new rollouts could potentially drop the task.
  • There is no receipt, ack of this fan-out execution of happening. Only looking at the logs (or sentry alerts) can give us some indication if a third-party integration fire has happened correctly. #123
  • There is no way to handle an attestation that came in the past, a.k.a replay
  • The firing logic is coupled to the service layer.

Lucky for us those shortcomings can be easily overcame by using an event bus / queue mechanism such as nats.io streams.

We should design a new architecture that fixes the aforementioned shortcomings and sets the stage to a generic third-party integration framework #38

Add Transparency Log viewing (Rekor based) to Chainloop

The current tool of choice to browse the TLog is https://rekor.tlog.dev/
I believe Chainloop could provide an alternative that is more in line with its scope of contract and materials verification.
We could, for example, combine the cosign verify-attestation CLI command with the Chainloop-centric contract verification flow.
In cosign, for a Github Action Workflow, this looks like:

Verification for my-container@sha256:<digest>
The following checks were performed on each of these signatures:
  - The cosign claims were validated
  - Existence of the claims in the transparency log was verified offline
  - The code-signing certificate was verified using trusted certificate authority certificates
Certificate subject:  <Subject>
Certificate issuer URL:  <OIDC Issuer URL>
GitHub Workflow Trigger: workflow_dispatch
GitHub Workflow SHA: <source code commit hash>
GitHub Workflow Name: <Workflow name>
GitHub Workflow Trigger: <Workflow repository>
GitHub Workflow Ref: <Workflow reference>

implement workflow describe

Currently, there is no option to describe a workflow, this means that there is not a consistent way to for example see the contract that's being used.

In fact there is a way but that requires listing the workflows and option for either a --full table output or json

chainloop wf ls --full
┌──────────────────────────────────────┬───────────────────┬──────────────────┬──────┬─────────────────────┬────────┬─────────────────┬─────────────────────┬──────────────────────────────────────┬──────────────────────────────────────┐
│ ID                                   │ NAME              │ PROJECT          │ TEAM │ CREATED AT          │ RUNNER │ LAST RUN STATUS │ LAST RUN AT         │ LAST RUN ID                          │ CONTRACT ID                          │
├──────────────────────────────────────┼───────────────────┼──────────────────┼──────┼─────────────────────┼────────┼─────────────────┼─────────────────────┼──────────────────────────────────────┼──────────────────────────────────────┤
│ 37022b2f-34c3-4f47-9fd7-514b4a7baaad │ build-and-release │ integration-demo │      │ 13 Jan 23 14:26 UTC │ GitHub │ success         │ 13 Jan 23 14:26 UTC │ 91093f6e-37c0-4e02-af5d-c9859596d125 │ c8f5d813-8f06-4b09-9593-f2122065d7ee │
└──────────────────────────────────────┴───────────────────┴──────────────────┴──────┴─────────────────────┴────────┴─────────────────┴─────────────────────┴──────────────────────────────────────┴──────────────────────────────────────┘
$ chainloop wf ls -o json
[
   {
      "name": "build-and-release",
      "id": "37022b2f-34c3-4f47-9fd7-514b4a7baaad",
      "team": "",
      "project": "integration-demo",
      "createdAt": "2023-01-13T14:26:34.224693Z",
      "runsCount": 17,
      "contractID": "c8f5d813-8f06-4b09-9593-f2122065d7ee",
      "lastRun": {
         "id": "91093f6e-37c0-4e02-af5d-c9859596d125",
         "state": "success",
         "createdAt": "2023-03-13T23:35:36.958669Z",
         "finishedAt": "2023-03-13T23:36:37.456564Z",
         "runURL": "https://github.com/chainloop-dev/integration-demo/actions/runs/4410543365",
         "runnerType": "GitHub"
      }
   }
]

This means that any client that wants to retrieve information such as the project name, the contract, etc needs to list the workflows instead. This works ok as long as we don't have pagination, but that will change in the future.

The goal of this task is

  • Add new API endpoint in the control plane to retrieve information about the workflow.
  • Implement chainloop workflow describe --id [id] that leverages that endpoint in the CLI.

For now, this command could return and render similar information to what the list endpoint does today (see json example above).

Remove OCI backend dependency from Controlplane

Currently, the controlplane has a dependency on a OCI backend provider so it can upload/download the generated attestation as well as downloading SBOMs for re-routing to Dependency-Track.

We have a component that it's already handling OCI upload/downloads which is the Artifact CAS, and this is leveraged by the CLI already.

We should delegate OCI access from the control plane to the artifact CAS and leverage its API instead this means.

  • Extract the CAS client code that it's currently in the CLI and move it to a top level package #43
  • Implement CAS upload use-case for attestation #45
  • Implement CAS download #46
  • Download attestation using CAS #46
  • Download SBOMs using CAS
  • Remove credentials.Reader and backend provider use from the control plane

Split attestation crafting steps

It's currently not possible to push an existing annotation to Chainloop without crafting one via Chainloop.
The desired behavior would be to allow users to push their own attestations (e.g generated via cosign) to Chainloop to leverage the workflow contract verification flow.

Extra work might be needed to extend the predicate definition in the contract schema.

Populate releases footer information

Goreleaser has a mechanism to add additional footer metadata to each release.

We could leverage this feature to add next steps such as the following in our .goreleaser.yml file

# https://goreleaser.com/customization/release/
release:
  footer: |
    - Read the [documentation](https://docs.chainloop.dev)
    - Join our [Discord server](https://discord.gg/Sfw3HnRt)

installation fails with sha256sum: command not found

The installation fails on OSX 13.3.1 with "sha256sum: command not found"

$ curl -sfL https://docs.chainloop.dev/install.sh | bash -s --
Step 1: Downloading: chainloop-cli-0.9.0-darwin-arm64.tar.gz
Done...

Step 1.2: Verifying checksum
bash: line 151: sha256sum: command not found

Use shasum -a 256 on OSX

Installation fails on OSX with "signature not found in transparency log"

Step 1: Downloading: chainloop-cli-0.9.0-darwin-arm64.tar.gz
Done...

Step 1.2: Verifying checksum
Checksum OK

Step 1.3: Verifying signature
Error: signature not found in transparency log
main.go:74: error during command execution: signature not found in transparency log

Cosign version:

GitVersion:    2.0.2
GitCommit:     871448050b924a7946ebe47678f23aae09ef432d
GitTreeState:  "clean"
BuildDate:     2023-04-24T17:31:42Z
GoVersion:     go1.20.3
Compiler:      gc
Platform:      darwin/arm64

Flaky integration tests in main module

The main module tests relies on Vault launched using testingContainers for integration tests. These seem to be flaky.

Note that we are using testing containers but with PostgreSQL in the backend and we've not noticed any flakiness, so I'd suggest to make sure the healthchecks and retries are properly set in this case.

--- FAIL: TestVaultIntegration (14.17s)
    --- FAIL: TestVaultIntegration/TestDeleteCreds (7.87s)
        keyval_test.go:125: 
            	Error Trace:	/home/runner/work/chainloop/chainloop/internal/credentials/vault/keyval_test.go:125
            	Error:      	Received unexpected error:
            	            	validating client: error writing secret to secret/data//chainloop-healthcheck: context deadline exceeded
            	Test:       	TestVaultIntegration/TestDeleteCreds
FAIL
FAIL	github.com/chainloop-dev/chainloop/internal/credentials/vault	14.177s
ok  	github.com/chainloop-dev/chainloop/internal/ociauth	0.003s
ok  	github.com/chainloop-dev/chainloop/internal/robotaccount/cas	0.035s

chart: improve installation output (notes.md)

Currently, once you install or upgrade the Chainloop Helm Chart you get this information

###########################################################################
  CONFIGURE CLI
###########################################################################

Configure the CLI to point to this instance, for example

  chainloop --insecure config save \
    --control-plane my-controlplane.acme.com:80 \
    --artifact-cas cas.acme.com:80

We could improve this output by actually showing you the command with the real hostname:port (my-controlplane.acme.com is a placeholder)

We could do this by checking if the services are set as load balancer or the ingresses has been configured. We can take a look at how some other Bitnami Charts do it [1] since the ingress logic has been mimicked from Bitnami Charts

handle invalid error during the OCI registry registration

The system raises an exception, and returns a 500 error to the user, during the creation of an OCI repository if the name is invalid.

*name.ErrBadName
repository can only contain the characters `abcdefghijklmnopqrstuvwxyz0123456789_-./`: [REPO_URI]

/home/runner/work/chainloop/chainloop/app/controlplane/internal/service/ocirepository.go in (*OCIRepositoryService).Save at line 56

This task is about

  • Make sure that the validation error gets exposed to the user, not just a generic 500 error
  • Do not record an exception in such case and just return validation error

deployment: split sentry configuration

Currently, the Helm Chart allows setting up a sentry.io endpoint to send exceptions to. But only accepts one set of settings that then gets injected in both the CAS and the Control Plane.

This task is about allowing setting different sentry.io projects both for the controlplane and for the CAS.

Merge OCI-repositories and Integration models

Chainloop control plane has a mechanism to forward received DSSE attestation envelopes or SBOMs to different backends, i.e OCI registry or Dependency-Track.

overview-2

This means that conceptually both OCI registries and SBOM processors are at the same level, third party fan out integrations, but reality is that the implementation grew in a different manner.

Because of historical development reasons, currently, an OCI repository is mapped as its own identity in both the database and business logic.

image

while dependency track integration makes use of a generic "integration" model meant to encapsulate different processors.

type Integration struct {
	ent.Schema
}

func (Integration) Fields() []ent.Field {
	return []ent.Field{
		field.UUID("id", uuid.UUID{}).Default(uuid.New).Unique().Immutable(),
		field.String("kind").Immutable(),
		field.String("secret_name").Immutable(),
		field.Time("created_at").
			Default(time.Now).
			Immutable().
			Annotations(&entsql.Annotation{Default: "CURRENT_TIMESTAMP"}),
		// kind specific config
		field.Bytes("config").GoType(&pb.IntegrationConfig{}),
		field.Time("deleted_at").Optional(),
	}
}

func (Integration) Edges() []ent.Edge {
	return []ent.Edge{
		edge.From("attachments", IntegrationAttachment.Type).Ref("integration"),
		edge.From("organization", Organization.Type).Ref("integrations").Unique().Required(),
	}
}

both of them belongs to an organization and get attached to different workflows. The only difference is that having a valid OCI registry is mandatory

This issue is about making the OCI repository feature part of the more generic "integrations" feature for consistency.

[fan-out integration] new SDK

UPDATE

This effort has evolved into creating a custom SDK for extensions that can be found here https://github.com/chainloop-dev/chainloop/tree/main/app/controlplane/extensions

NOTE: We should make sure that whatever design we make here meets also this #28 other effort.

Currently, adding a third party integration requires changes in many places in the control-plane codebase as described here #37 (comment). In short it requires changes is pretty much every layer of the application, a) api proto changes, b) biz/use-cases changes and of course c) actual integration code.

c) is the only part that's clearly defined with interfaces

type Checker interface {
// Validate that the integration can be registered for future calls
Validate(ctx context.Context) error
}
type Doer interface {
Do(ctx context.Context) error
// Validate that the integration can be performed with the parameters provided
Validate(ctx context.Context) error
}

The other two changes are currently custom and per-integration.

The goal of this effort is to design an architecture where adding a new integration just requires such custom code to implement some interfaces, custom code that should probably live in https://github.com/chainloop-dev/chainloop/tree/e770faeeed854cfcff45a06100f9a2eef57d779a/app/controlplane/internal/integrations

Some goals

  • These new interfaces should cover the "registration" and "attachment" use cases
  • We should aim to no code changes required for a new attestation in the biz, service or API layer

Tasks

No tasks being tracked yet.

Policy check on received attestation

Currently, no verification is done when an attestation is received in the control plane. Creation and validation checks are done in the client side, but not on the server side.

We should allow operators to attach rego or potentially cue policies to their contracts and these should get evaluated during the reception of the attestation.

We created a task #35 which will get superseded by this functionality since 35 is in fact a policy check that some materials exist and that the runner type is correct.

re: implementation

  • We can start with making this check an enforcement, meaning that if the policy check fails the att push command will too since the check for the first version could be sync.
  • We could implement this check as a fan-out integration. Create it by default in your org and automatically attach it to each of your workflows.

About the policy format.

We should probably aim towards Open Policy Agent (OPA) and leverage (conftest) logic. We should take a look at policy-controller way of doing this

On the UX side of things we could allow attaching a policy to our contract today.

example from policy-controller that could map our current contract too.

using cue

policy:
        type: cue
        data: |
          predicateType: "https://cosign.sigstore.dev/attestation/v1"
          predicate: "foobar e2e test"

or rego

policy:
        type: rego
        data: |
          package sigstore
          default isCompliant = false
          isCompliant {
            input.predicateType == "https://cosign.sigstore.dev/attestation/v1"
            input.predicate == "foobar e2e test"
          }

Note: If we go ahead with the implementation based on an integration. We would need to extend the integrations model to read from its result and apply it to the workflow runs. Currently they are just fire and forget.

support workflow update

Currently, once a workflow is create with a name project, team and optionally a contract, it can not be changed.

We should allow user to be able to

  • update metadata such as name, team or project
  • associate the workflow with another contract

Note that the latest point can be a breaking change to existing pipelines, so we should make sure that if the user asks to change the workflow we show a confirmation prompt.

From the CLI this could be implemented using the same flags and behavior we have on workflow create

chainloop wf update --id [requiredID] \
  --name [optional] \
  --project [optional] \
  --team [optional] \ 
  --contract [optional ID of an existing contract or path to a new one]

Some implementation caveats

  • Not providing any of those flags means no change on those properties
  • We should show a confirmation prompt when the intent is to update the contract

Implementation overview

  • Add wf update API endpoint in Control Plane, including proto definitions, service and use-cases implementation
  • Implement CLI command

Extract attestation grpc service to another proto file

Currently app/controlplane/api/controlplane/v1/workflow_run.proto has two services defined, one associated with workflow runs operations and another one about the attestation process.

service AttestationService {
rpc GetContract (AttestationServiceGetContractRequest) returns (AttestationServiceGetContractResponse);
rpc Init (AttestationServiceInitRequest) returns (AttestationServiceInitResponse);
rpc Store (AttestationServiceStoreRequest) returns (AttestationServiceStoreResponse);
// There is another endpoint to get credentials via casCredentialsService.Get
// This one is kept since it leverages robot-accounts in the context of a workflow
rpc GetUploadCreds (AttestationServiceGetUploadCredsRequest) returns (AttestationServiceGetUploadCredsResponse);
rpc Cancel (AttestationServiceCancelRequest) returns (AttestationServiceCancelResponse);
}
// Administrative service for the operator
service WorkflowRunService {
rpc List (WorkflowRunServiceListRequest) returns (WorkflowRunServiceListResponse);
rpc View (WorkflowRunServiceViewRequest) returns (WorkflowRunServiceViewResponse);
}

This task is about extracting the AttestationService (and associated req/resp payloads) to another proto file in the same proto package.

Handle AWS secret manager empty response

We've received this exception

{"level":"error", "msg":"runtime error: invalid memory address or nil pointer dereference: 
goroutine 25579 [running]:
github.com/go-kratos/kratos/v2/middleware/recovery.Recovery.func2.1.1()
	/home/runner/go/pkg/mod/github.com/go-kratos/kratos/[email protected]/middleware/recovery/recovery.go:53 +0xa7
panic({0x2185140, 0x3b16820})
	/opt/hostedtoolcache/go/1.20.2/x64/src/runtime/panic.go:884 +0x213
github.com/chainloop-dev/chainloop/internal/credentials/aws.(*Manager).ReadCredentials(0xc0006747b0, {0x28df088, 0xc000f01740}, {0xc000e8a660, 0x58}, {0x213dea0, 0xc000e0b2c0})
	/home/runner/work/chainloop/chainloop/internal/credentials/aws/secretmanager.go:123 +0x150
github.com/chainloop-dev/chainloop/internal/blobmanager/oci.(*BackendProvider).FromCredentials(0xc000752e20, {0x28df088, 0xc000f01740}, {0xc000e8a660, 0x58})
	/home/runner/work/chainloop/chainloop/internal/blobmanager/oci/provider.go:39 +0x93
github.com/chainloop-dev/chainloop/app/controlplane/internal/biz.(*OCIRepositoryUseCase).PerformValidation(0xc000704040, {0x28df088, 0xc000f01740}, {0xc0010e5260, 0x24})

The nil pointer is raised here

return json.Unmarshal([]byte(*resp.SecretString), creds)

It seems that for some reason both resp and err were nil?

in-toto 1.0 support

In-toto 1.0 has been released 🎉 and it includes a couple of major enhancements that seem relevant to the Chainloop project.

New upstream predicates and guidelines available

Chainloop uses a custom predicate chainloop.dev/attestation/v0.1. We should re-evaluate the need of our custom predicate or use an existing one. If we still do, we should make sure it adheres to the guidelines and if it would make sense to try to upstream it.

Attestation bundle

The new attestation bundle can be specially handy in the context of #53. It will allow us to bundle not only the Chainloop generated DSSE envelope but any other generated envelope.

For extensibility in the future, it might be a good idea to default to a bundle for communication with the control-plane

Resource descriptor

Currently Chainloop encodes the materials in the attestation like this. It's basically an extension of a slsa material (with digest and URI) plus some additional metadata used by the Chainloop controlplane for validation and routing (name and type)

The new resource descriptor might be a good fit to replace that custom type. The annotations field could contain the custom chainloop types.

 "materials": [
      {
        "material": {
          "slsa": {
            "digest": {
              "sha256": "7e5f829611edeedf36a7318f78e6914b85a8e2f90ac8628cc868b2e87204d93b"
            },
            "uri": "ghcr.io/chainloop-dev/frontend"
          }
        },
        "name": "frontend",
        "type": "CONTAINER_IMAGE"
      },
      {
        "material": {
          "slsa": {
            "digest": {
              "sha256": "092252ea069679c658a949748ca0bee9405d36630d6b460964c7225708de0bb5"
            },
            "uri": "sbom.cyclonedx.json"
          }
        },
        "name": "frontend-sbom",
        "type": "SBOM_CYCLONEDX_JSON"
      }
    ],

Congrats @adityasaky, @TomHennen and rest of the team for the release!

Feel free to drop any thoughts or comments, always appreciated!

TODO

  • Look into attestation bundles
  • Resource descriptors in predicate materials
  • Resource descriptors as subject items

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.