Skip to content

Commit

Permalink
Add support for bearer token auth in Prow Jenkins controller
Browse files Browse the repository at this point in the history
Not all Jenkins masters allow for basic auth. This patch adds support
for bearer token auth in the Prow Jenkins client.

Signed-off-by: Steve Kuznetsov <[email protected]>
  • Loading branch information
stevekuznetsov committed Aug 29, 2017
1 parent a062a81 commit d9860bb
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 26 deletions.
1 change: 1 addition & 0 deletions prow/cluster/deck_deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ spec:
containerPort: 8080
args:
- --jenkins-url=$(JENKINS_URL)
- --jenkins-token=/etc/jenkins/jenkins
- --build-cluster=/etc/cluster/cluster
env:
- name: JENKINS_URL
Expand Down
1 change: 1 addition & 0 deletions prow/cluster/jenkins_deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ spec:
image: gcr.io/k8s-prow/jenkins-operator:0.39
args:
- --dry-run=false
- --jenkins-token=/etc/jenkins/jenkins
volumeMounts:
- mountPath: /etc/jenkins
name: jenkins
Expand Down
41 changes: 33 additions & 8 deletions prow/cmd/deck/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,10 @@ var (
configPath = flag.String("config-path", "/etc/config/config", "Path to config.yaml.")
buildCluster = flag.String("build-cluster", "", "Path to file containing a YAML-marshalled kube.Cluster object. If empty, uses the local cluster.")

jenkinsURL = flag.String("jenkins-url", "", "Jenkins URL")
jenkinsUserName = flag.String("jenkins-user", "jenkins-trigger", "Jenkins username")
jenkinsTokenFile = flag.String("jenkins-token-file", "/etc/jenkins/jenkins", "Path to the file containing the Jenkins API token.")
jenkinsURL = flag.String("jenkins-url", "", "Jenkins URL")
jenkinsUserName = flag.String("jenkins-user", "jenkins-trigger", "Jenkins username")
jenkinsTokenFile = flag.String("jenkins-token-file", "", "Path to the file containing the Jenkins API token.")
jenkinsBearerTokenFile = flag.String("jenkins-bearer-token-file", "", "Path to the file containing the Jenkins API bearer token.")
)

// Matches letters, numbers, hyphens, and underscores.
Expand Down Expand Up @@ -70,14 +71,30 @@ func main() {
}
}

var ac *jenkins.AuthConfig
var jc *jenkins.Client
if *jenkinsURL != "" {
jenkinsSecretRaw, err := ioutil.ReadFile(*jenkinsTokenFile)
if err != nil {
logrus.WithError(err).Fatalf("Could not read token file.")
if *jenkinsTokenFile != "" {
if token, err := loadToken(*jenkinsTokenFile); err != nil {
logrus.WithError(err).Fatalf("Could not read token file.")
} else {
ac.Basic = &jenkins.BasicAuthConfig{
User: *jenkinsUserName,
Token: token,
}
}
} else if *jenkinsBearerTokenFile != "" {
if token, err := loadToken(*jenkinsBearerTokenFile); err != nil {
logrus.WithError(err).Fatalf("Could not read token file.")
} else {
ac.BearerToken = &jenkins.BearerTokenAuthConfig{
Token: token,
}
}
} else {
logrus.Fatal("An auth token for basic or bearer token auth must be supplied.")
}
jenkinsToken := string(bytes.TrimSpace(jenkinsSecretRaw))
jc = jenkins.NewClient(*jenkinsURL, *jenkinsUserName, jenkinsToken)
jc = jenkins.NewClient(*jenkinsURL, ac)
}

ja := &JobAgent{
Expand All @@ -95,6 +112,14 @@ func main() {
logrus.WithError(http.ListenAndServe(":8080", nil)).Fatal("ListenAndServe returned.")
}

func loadToken(file string) (string, error) {
raw, err := ioutil.ReadFile(file)
if err != nil {
return "", err
}
return string(bytes.TrimSpace(raw)), nil
}

func handleData(ja *JobAgent) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Cache-Control", "no-cache")
Expand Down
41 changes: 33 additions & 8 deletions prow/cmd/jenkins-operator/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,10 @@ import (
var (
configPath = flag.String("config-path", "/etc/config/config", "Path to config.yaml.")

jenkinsURL = flag.String("jenkins-url", "http://jenkins-proxy", "Jenkins URL")
jenkinsUserName = flag.String("jenkins-user", "jenkins-trigger", "Jenkins username")
jenkinsTokenFile = flag.String("jenkins-token-file", "/etc/jenkins/jenkins", "Path to the file containing the Jenkins API token.")
jenkinsURL = flag.String("jenkins-url", "http://jenkins-proxy", "Jenkins URL")
jenkinsUserName = flag.String("jenkins-user", "jenkins-trigger", "Jenkins username")
jenkinsTokenFile = flag.String("jenkins-token-file", "", "Path to the file containing the Jenkins API token.")
jenkinsBearerTokenFile = flag.String("jenkins-bearer-token-file", "", "Path to the file containing the Jenkins API bearer token.")

_ = flag.String("github-bot-name", "", "Deprecated.")
githubEndpoint = flag.String("github-endpoint", "https://api.github.com", "GitHub's API endpoint.")
Expand All @@ -58,12 +59,28 @@ func main() {
logrus.WithError(err).Fatal("Error getting kube client.")
}

jenkinsSecretRaw, err := ioutil.ReadFile(*jenkinsTokenFile)
if err != nil {
logrus.WithError(err).Fatalf("Could not read Jenkins token file.")
var ac *jenkins.AuthConfig
if *jenkinsTokenFile != "" {
token, err := loadToken(*jenkinsTokenFile)
if err != nil {
logrus.WithError(err).Fatalf("Could not read token file.")
}
ac.Basic = &jenkins.BasicAuthConfig{
User: *jenkinsUserName,
Token: token,
}
} else if *jenkinsBearerTokenFile != "" {
token, err := loadToken(*jenkinsBearerTokenFile)
if err != nil {
logrus.WithError(err).Fatalf("Could not read bearer token file.")
}
ac.BearerToken = &jenkins.BearerTokenAuthConfig{
Token: token,
}
} else {
logrus.Fatal("An auth token for basic or bearer token auth must be supplied.")
}
jenkinsToken := string(bytes.TrimSpace(jenkinsSecretRaw))
jc := jenkins.NewClient(*jenkinsURL, *jenkinsUserName, jenkinsToken)
jc := jenkins.NewClient(*jenkinsURL, ac)

oauthSecretRaw, err := ioutil.ReadFile(*githubTokenFile)
if err != nil {
Expand Down Expand Up @@ -95,3 +112,11 @@ func main() {
logrus.Infof("Sync time: %v", time.Since(start))
}
}

func loadToken(file string) (string, error) {
raw, err := ioutil.ReadFile(file)
if err != nil {
return "", err
}
return string(bytes.TrimSpace(raw)), nil
}
39 changes: 29 additions & 10 deletions prow/jenkins/jenkins.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,25 @@ type Status struct {
}

type Client struct {
client *http.Client
baseURL string
user string
token string
client *http.Client
baseURL string
authConfig *AuthConfig
}

// AuthConfig configures how we auth with Jenkins.
// Only one of the fields will be non-nil.
type AuthConfig struct {
Basic *BasicAuthConfig
BearerToken *BearerTokenAuthConfig
}

type BasicAuthConfig struct {
User string
Token string
}

type BearerTokenAuthConfig struct {
Token string
}

type BuildRequest struct {
Expand All @@ -64,12 +79,11 @@ type Build struct {
QueueURL *url.URL
}

func NewClient(url, user, token string) *Client {
func NewClient(url string, authConfig *AuthConfig) *Client {
return &Client{
baseURL: url,
user: user,
token: token,
client: &http.Client{},
baseURL: url,
authConfig: authConfig,
client: &http.Client{},
}
}

Expand Down Expand Up @@ -97,7 +111,12 @@ func (c *Client) doRequest(method, path string) (*http.Response, error) {
if err != nil {
return nil, err
}
req.SetBasicAuth(c.user, c.token)
if c.authConfig.Basic != nil {
req.SetBasicAuth(c.authConfig.Basic.User, c.authConfig.Basic.Token)
}
if c.authConfig.BearerToken != nil {
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", c.authConfig.BearerToken.Token))
}
return c.client.Do(req)
}

Expand Down

0 comments on commit d9860bb

Please sign in to comment.