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

Add Jenkins scanning #2892

Merged
merged 4 commits into from
Jun 4, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

---

# :mag_right: *Now Scanning*
# :mag_right: _Now Scanning_

<div align="center">

Expand Down Expand Up @@ -267,6 +267,12 @@ Use the `--workspace-id`, `--collection-id`, `--environment` flags multiple time
trufflehog postman --token=<postman api token> --workspace-id=<workspace id>
```

## 13: Scan a Jenkins server

```bash
trufflehog jenkins --url https://jenkins.example.com --username admin --password admin
```

# :question: FAQ

- All I see is `🐷🔑🐷 TruffleHog. Unearth your secrets. 🐷🔑🐷` and the program exits, what gives?
Expand Down Expand Up @@ -307,6 +313,8 @@ TruffleHog has a sub-command for each source of data that you may want to scan:
- travisci
- gcs (Google Cloud Storage)
- postman
- jenkins
- elasticsearch

Each subcommand can have options that you can see with the `--help` flag provided to the sub command:

Expand Down Expand Up @@ -672,4 +680,3 @@ the stability of the public APIs at this time.
# License Change

Since v3.0, TruffleHog is released under a AGPL 3 license, included in [`LICENSE`](LICENSE). TruffleHog v3.0 uses none of the previous codebase, but care was taken to preserve backwards compatibility on the command line interface. The work previous to this release is still available licensed under GPL 2.0 in the history of this repository and the previous package releases and tags. A completed CLA is required for us to accept contributions going forward.

203 changes: 105 additions & 98 deletions assets/scanning_logos.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 16 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,12 @@ var (
elasticsearchQueryJSON = elasticsearchScan.Flag("query-json", "Filters the documents to search").Envar("ELASTICSEARCH_QUERY_JSON").String()
elasticsearchSinceTimestamp = elasticsearchScan.Flag("since-timestamp", "Filters the documents to search to those created since this timestamp; overrides any timestamp from --query-json").Envar("ELASTICSEARCH_SINCE_TIMESTAMP").String()
elasticsearchBestEffortScan = elasticsearchScan.Flag("best-effort-scan", "Attempts to continuously scan a cluster").Envar("ELASTICSEARCH_BEST_EFFORT_SCAN").Bool()

jenkinsScan = cli.Command("jenkins", "Scan Jenkins")
jenkinsURL = jenkinsScan.Flag("url", "Jenkins URL").Envar("JENKINS_URL").Required().String()
jenkinsUsername = jenkinsScan.Flag("username", "Jenkins username").Envar("JENKINS_USERNAME").String()
jenkinsPassword = jenkinsScan.Flag("password", "Jenkins password").Envar("JENKINS_PASSWORD").String()
jenkinsInsecureSkipVerifyTLS = jenkinsScan.Flag("insecure-skip-verify-tls", "Skip TLS verification").Envar("JENKINS_INSECURE_SKIP_VERIFY_TLS").Bool()
)

func init() {
Expand Down Expand Up @@ -661,6 +667,16 @@ func run(state overseer.State) {
if err := e.ScanElasticsearch(ctx, cfg); err != nil {
logFatal(err, "Failed to scan Elasticsearch.")
}
case jenkinsScan.FullCommand():
cfg := engine.JenkinsConfig{
Endpoint: *jenkinsURL,
InsecureSkipVerifyTLS: *jenkinsInsecureSkipVerifyTLS,
Username: *jenkinsUsername,
Password: *jenkinsPassword,
}
if err := e.ScanJenkins(ctx, cfg); err != nil {
logFatal(err, "Failed to scan Jenkins.")
}
default:
logFatal(fmt.Errorf("invalid command"), "Command not recognized.")
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/detectors/privatekey/privatekey_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ func Test_lookupFingerprint(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
gotFingerprints, err := lookupFingerprint(tt.publicKeyFingerprintInHex, tt.includeExpired)
gotFingerprints, err := lookupFingerprint(context.TODO(), tt.publicKeyFingerprintInHex, tt.includeExpired)
if (err != nil) != tt.wantErr {
t.Errorf("lookupFingerprint() error = %v, wantErr %v", err, tt.wantErr)
return
Expand Down
78 changes: 78 additions & 0 deletions pkg/engine/jenkins.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package engine

import (
"errors"
"runtime"
"strings"

"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/types/known/anypb"

"github.com/trufflesecurity/trufflehog/v3/pkg/context"
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/credentialspb"
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/sourcespb"
"github.com/trufflesecurity/trufflehog/v3/pkg/sources/circleci"
"github.com/trufflesecurity/trufflehog/v3/pkg/sources/jenkins"
)

type JenkinsConfig struct {
Endpoint string
Username string
Password string
Header string
InsecureSkipVerifyTLS bool
}

// ScanJenkins scans Jenkins logs.
func (e *Engine) ScanJenkins(ctx context.Context, jenkinsConfig JenkinsConfig) error {
var connection *sourcespb.Jenkins
switch {
case jenkinsConfig.Username != "" && jenkinsConfig.Password != "":
connection = &sourcespb.Jenkins{
Credential: &sourcespb.Jenkins_BasicAuth{
BasicAuth: &credentialspb.BasicAuth{
Username: jenkinsConfig.Username,
Password: jenkinsConfig.Password,
},
},
}
case jenkinsConfig.Header != "":
splits := strings.Split(jenkinsConfig.Header, ":")
if len(splits) != 2 {
return errors.New("invalid header format, expected key: value")
}
key := splits[0]
value := splits[1]

connection = &sourcespb.Jenkins{
Credential: &sourcespb.Jenkins_Header{
Header: &credentialspb.Header{
Key: key,
Value: value,
},
},
}
default:
return errors.New("invalid Jenkins configuration")
}

connection.Endpoint = jenkinsConfig.Endpoint
connection.InsecureSkipVerifyTls = jenkinsConfig.InsecureSkipVerifyTLS

var conn anypb.Any
err := anypb.MarshalFrom(&conn, connection, proto.MarshalOptions{})
if err != nil {
ctx.Logger().Error(err, "failed to marshal Jenkins connection")
return err
}

sourceName := "trufflehog - Jenkins"
sourceID, jobID, _ := e.sourceManager.GetIDs(ctx, sourceName, circleci.SourceType)

jenkinsSource := &jenkins.Source{}
if err := jenkinsSource.Init(ctx, "trufflehog - Jenkins", jobID, sourceID, true, &conn, runtime.NumCPU()); err != nil {
return err
}
_, err = e.sourceManager.Run(ctx, sourceName, jenkinsSource)
return err
}
Loading
Loading