From 11e2ee6b95df27c3be3952a26b3baeb40d0af9b3 Mon Sep 17 00:00:00 2001 From: Jef LeCompte Date: Fri, 26 Jun 2020 19:44:40 -0400 Subject: [PATCH] feat: initial release (#1) --- .github/workflows/ci.yaml | 10 ++-- Dockerfile | 23 +++++++ Makefile | 43 +++++++++++++ README.md | 2 +- go.mod | 3 + go.sum | 0 main.go | 123 ++++++++++++++++++++++++++++++++++++++ 7 files changed, 199 insertions(+), 5 deletions(-) create mode 100644 Dockerfile create mode 100644 Makefile create mode 100644 go.mod create mode 100644 go.sum create mode 100644 main.go diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index ef75964..54e46ee 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -14,8 +14,8 @@ jobs: key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} restore-keys: | ${{ runner.os }}-go- - - name: Pull dependencies - run: make build + - name: Build + run: make production lint: runs-on: ubuntu-latest steps: @@ -29,5 +29,7 @@ jobs: key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} restore-keys: | ${{ runner.os }}-go- - - name: Pull dependencies - run: make lint + - name: Lint + run: | + go get -u golang.org/x/lint/golint + golint -set_exit_status diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..ba976d4 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,23 @@ +FROM golang:1.14.4-alpine3.11 AS builder + +RUN apk update && apk --no-cache add make git + +WORKDIR /build + +ARG GITHUB_ORGANIZATION +ARG GITHUB_PAT + +COPY go.mod go.mod +COPY go.sum go.sum +COPY main.go main.go +COPY Makefile Makefile + +RUN make production + +FROM scratch + +WORKDIR /opt + +COPY --from=builder /build/bin/audit-org-keys audit-org-keys + +ENTRYPOINT ["./audit-org-keys"] diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..475afba --- /dev/null +++ b/Makefile @@ -0,0 +1,43 @@ +PROJECT_NAME=audit-org-keys +GOBASE=$(shell pwd) +GOBIN=$(GOBASE)/bin/$(PROJECT_NAME) + +.DEFAULT_GOAL := build + +build: + go build -o $(GOBIN) + +build-docker: + docker build \ + --build-arg "GITHUB_ORGANIZATION=$(GITHUB_ORGANIZATION)" \ + --build-arg "GITHUB_PAT=$(GITHUB_PAT)" \ + -t $(PROJECT_NAME):local . + +clean: + rm -rf $(GOBIN) + +fmt: + go fmt + +hooks: + cp -f .github/hooks/pre-commit .git/hooks/pre-commit + +install: + go mod download + +production: + CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" -o $(GOBIN) + +run: + make build + $(GOBIN) + +run-docker: + make build-docker + docker run --rm -it $(PROJECT_NAME):local + +test: + go test -v + +vet: + go vet -v diff --git a/README.md b/README.md index 876707a..89a3b70 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# audit-org-keys +# audit-org-keys [![ci](https://github.com/jef/audit-org-keys/workflows/ci/badge.svg)](https://github.com/jef/audit-org-keys/actions?query=workflow%3Aci) The point of this project is to help demonstrate that users of GitHub could potentially fall victim to getting their private SSH key cracked. This based on the size and complexity of the key the user generates. diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..078a42d --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module github.com/jef/audit-org-keys + +go 1.14 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..e69de29 diff --git a/main.go b/main.go new file mode 100644 index 0000000..133af0f --- /dev/null +++ b/main.go @@ -0,0 +1,123 @@ +package main + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "log" + "net/http" + "os" +) + +const ( + githubURL = "https://github.com" + githubOrgsAPI = "https://api.github.com/orgs" +) + +var ( + githubOrg = os.Getenv("GITHUB_ORGANIZATION") + githubPat = os.Getenv("GITHUB_PAT") +) + +type member struct { + Login string `json:"login"` +} + +func main() { + fmt.Println("getting members") + members := getMembers() + + fmt.Println("getting keys") + getKeys(members) +} + +func getKeys(members []member) { + client := &http.Client{} + + var membersWithNoKey []member + + for _, member := range members { + req, err := http.NewRequest( + "GET", + fmt.Sprintf("%s/%s.keys", githubURL, member.Login), + nil, + ) + if err != nil { + log.Fatal(err) + } + req.Header.Add("authorization", fmt.Sprintf("token %s", githubPat)) + + res, err := client.Do(req) + if err != nil { + log.Fatal(err) + } + + defer res.Body.Close() + + key, err := ioutil.ReadAll(res.Body) + if err != nil { + log.Fatal(err) + } + + if len(key) != 0 { + fmt.Println(fmt.Sprintf("%s:\n%s", member.Login, key)) + fmt.Println("-------------------------------------------------------------------------------------") + fmt.Println() + } else { + membersWithNoKey = append(membersWithNoKey, member) + } + } + + fmt.Println(fmt.Sprintf("members with no keys (%d):", len(membersWithNoKey))) + for _, member := range membersWithNoKey { + fmt.Println(fmt.Sprintf("%s", member.Login)) + } +} + +func getMembers() []member { + page := 1 + + var members []member + + for { + client := &http.Client{} + + req, err := http.NewRequest( + "GET", + fmt.Sprintf("%s/%s/members?filter=all&page=%d", githubOrgsAPI, githubOrg, page), + nil, + ) + if err != nil { + log.Fatal(err) + } + req.Header.Add("authorization", fmt.Sprintf("token %s", githubPat)) + + res, err := client.Do(req) + if err != nil { + log.Fatal(err) + } + + defer res.Body.Close() + + body, err := ioutil.ReadAll(res.Body) + if err != nil { + log.Fatal(err) + } + + var ms []member + + err = json.Unmarshal(body, &ms) + if err != nil { + log.Fatal(err) + } + + if len(ms) != 0 { + members = append(members, ms...) + page++ + } else { + break + } + } + + return members +}