Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
K
k3s
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Jacklull
k3s
Commits
f34bb50c
Commit
f34bb50c
authored
Oct 24, 2016
by
deads2k
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
add x509 verifier
parent
2f756e4e
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
224 additions
and
6 deletions
+224
-6
x509.go
plugin/pkg/auth/authenticator/request/x509/x509.go
+58
-0
x509_test.go
plugin/pkg/auth/authenticator/request/x509/x509_test.go
+166
-6
No files found.
plugin/pkg/auth/authenticator/request/x509/x509.go
View file @
f34bb50c
...
...
@@ -18,11 +18,17 @@ package x509
import
(
"crypto/x509"
"crypto/x509/pkix"
"encoding/asn1"
"fmt"
"net/http"
"github.com/golang/glog"
"k8s.io/kubernetes/pkg/auth/authenticator"
"k8s.io/kubernetes/pkg/auth/user"
utilerrors
"k8s.io/kubernetes/pkg/util/errors"
"k8s.io/kubernetes/pkg/util/sets"
)
// UserConversion defines an interface for extracting user info from a client certificate chain
...
...
@@ -85,6 +91,58 @@ func (a *Authenticator) AuthenticateRequest(req *http.Request) (user.Info, bool,
return
nil
,
false
,
utilerrors
.
NewAggregate
(
errlist
)
}
// Verifier implements request.Authenticator by verifying a client cert on the request, then delegating to the wrapped auth
type
Verifier
struct
{
opts
x509
.
VerifyOptions
auth
authenticator
.
Request
// allowedCommonNames contains the common names which a verified certificate is allowed to have.
// If empty, all verified certificates are allowed.
allowedCommonNames
sets
.
String
}
// NewVerifier create a request.Authenticator by verifying a client cert on the request, then delegating to the wrapped auth
func
NewVerifier
(
opts
x509
.
VerifyOptions
,
auth
authenticator
.
Request
,
allowedCommonNames
sets
.
String
)
authenticator
.
Request
{
return
&
Verifier
{
opts
,
auth
,
allowedCommonNames
}
}
// AuthenticateRequest verifies the presented client certificate, then delegates to the wrapped auth
func
(
a
*
Verifier
)
AuthenticateRequest
(
req
*
http
.
Request
)
(
user
.
Info
,
bool
,
error
)
{
if
req
.
TLS
==
nil
||
len
(
req
.
TLS
.
PeerCertificates
)
==
0
{
return
nil
,
false
,
nil
}
// Use intermediates, if provided
optsCopy
:=
a
.
opts
if
optsCopy
.
Intermediates
==
nil
&&
len
(
req
.
TLS
.
PeerCertificates
)
>
1
{
optsCopy
.
Intermediates
=
x509
.
NewCertPool
()
for
_
,
intermediate
:=
range
req
.
TLS
.
PeerCertificates
[
1
:
]
{
optsCopy
.
Intermediates
.
AddCert
(
intermediate
)
}
}
if
_
,
err
:=
req
.
TLS
.
PeerCertificates
[
0
]
.
Verify
(
optsCopy
);
err
!=
nil
{
return
nil
,
false
,
err
}
if
err
:=
a
.
verifySubject
(
req
.
TLS
.
PeerCertificates
[
0
]
.
Subject
);
err
!=
nil
{
return
nil
,
false
,
err
}
return
a
.
auth
.
AuthenticateRequest
(
req
)
}
func
(
a
*
Verifier
)
verifySubject
(
subject
pkix
.
Name
)
error
{
// No CN restrictions
if
len
(
a
.
allowedCommonNames
)
==
0
{
return
nil
}
// Enforce CN restrictions
if
a
.
allowedCommonNames
.
Has
(
subject
.
CommonName
)
{
return
nil
}
glog
.
Warningf
(
"x509: subject with cn=%s is not in the allowed list: %v"
,
subject
.
CommonName
,
a
.
allowedCommonNames
.
List
())
return
fmt
.
Errorf
(
"x509: subject with cn=%s is not allowed"
,
subject
.
CommonName
)
}
// DefaultVerifyOptions returns VerifyOptions that use the system root certificates, current time,
// and requires certificates to be valid for client auth (x509.ExtKeyUsageClientAuth)
func
DefaultVerifyOptions
()
x509
.
VerifyOptions
{
...
...
plugin/pkg/auth/authenticator/request/x509/x509_test.go
View file @
f34bb50c
...
...
@@ -28,7 +28,9 @@ import (
"testing"
"time"
"k8s.io/kubernetes/pkg/auth/authenticator"
"k8s.io/kubernetes/pkg/auth/user"
"k8s.io/kubernetes/pkg/util/sets"
)
const
(
...
...
@@ -373,12 +375,12 @@ mFlG6tStAWz3TmydciZNdiEbeqHw5uaIYWj1zC5AdvFXBFue0ojIrJ5JtbTWccH9
`
/*
openssl genrsa -out ca.key 4096
openssl req -new -x509 -days 36500 \
-sha256 -key ca.key -extensions v3_ca \
-out ca.crt \
-subj "/C=US/ST=My State/L=My City/O=My Org/O=My Org 1/O=My Org 2/CN=ROOT CA WITH GROUPS"
openssl x509 -in ca.crt -text
openssl genrsa -out ca.key 4096
openssl req -new -x509 -days 36500 \
-sha256 -key ca.key -extensions v3_ca \
-out ca.crt \
-subj "/C=US/ST=My State/L=My City/O=My Org/O=My Org 1/O=My Org 2/CN=ROOT CA WITH GROUPS"
openssl x509 -in ca.crt -text
*/
// A certificate with multiple organizations.
...
...
@@ -723,6 +725,164 @@ func TestX509(t *testing.T) {
}
}
func
TestX509Verifier
(
t
*
testing
.
T
)
{
multilevelOpts
:=
DefaultVerifyOptions
()
multilevelOpts
.
Roots
=
x509
.
NewCertPool
()
multilevelOpts
.
Roots
.
AddCert
(
getCertsFromFile
(
t
,
"root"
)[
0
])
testCases
:=
map
[
string
]
struct
{
Insecure
bool
Certs
[]
*
x509
.
Certificate
Opts
x509
.
VerifyOptions
AllowedCNs
sets
.
String
ExpectOK
bool
ExpectErr
bool
}{
"non-tls"
:
{
Insecure
:
true
,
ExpectOK
:
false
,
ExpectErr
:
false
,
},
"tls, no certs"
:
{
ExpectOK
:
false
,
ExpectErr
:
false
,
},
"self signed"
:
{
Opts
:
getDefaultVerifyOptions
(
t
),
Certs
:
getCerts
(
t
,
selfSignedCert
),
ExpectErr
:
true
,
},
"server cert disallowed"
:
{
Opts
:
getDefaultVerifyOptions
(
t
),
Certs
:
getCerts
(
t
,
serverCert
),
ExpectErr
:
true
,
},
"server cert allowing non-client cert usages"
:
{
Opts
:
x509
.
VerifyOptions
{
Roots
:
getRootCertPool
(
t
)},
Certs
:
getCerts
(
t
,
serverCert
),
ExpectOK
:
true
,
ExpectErr
:
false
,
},
"valid client cert"
:
{
Opts
:
getDefaultVerifyOptions
(
t
),
Certs
:
getCerts
(
t
,
clientCNCert
),
ExpectOK
:
true
,
ExpectErr
:
false
,
},
"valid client cert with wrong CN"
:
{
Opts
:
getDefaultVerifyOptions
(
t
),
AllowedCNs
:
sets
.
NewString
(
"foo"
,
"bar"
),
Certs
:
getCerts
(
t
,
clientCNCert
),
ExpectOK
:
false
,
ExpectErr
:
true
,
},
"valid client cert with right CN"
:
{
Opts
:
getDefaultVerifyOptions
(
t
),
AllowedCNs
:
sets
.
NewString
(
"client_cn"
),
Certs
:
getCerts
(
t
,
clientCNCert
),
ExpectOK
:
true
,
ExpectErr
:
false
,
},
"future cert"
:
{
Opts
:
x509
.
VerifyOptions
{
CurrentTime
:
time
.
Now
()
.
Add
(
-
100
*
time
.
Hour
*
24
*
365
),
Roots
:
getRootCertPool
(
t
),
},
Certs
:
getCerts
(
t
,
clientCNCert
),
ExpectOK
:
false
,
ExpectErr
:
true
,
},
"expired cert"
:
{
Opts
:
x509
.
VerifyOptions
{
CurrentTime
:
time
.
Now
()
.
Add
(
100
*
time
.
Hour
*
24
*
365
),
Roots
:
getRootCertPool
(
t
),
},
Certs
:
getCerts
(
t
,
clientCNCert
),
ExpectOK
:
false
,
ExpectErr
:
true
,
},
"multi-level, valid"
:
{
Opts
:
multilevelOpts
,
Certs
:
getCertsFromFile
(
t
,
"client-valid"
,
"intermediate"
),
ExpectOK
:
true
,
ExpectErr
:
false
,
},
"multi-level, expired"
:
{
Opts
:
multilevelOpts
,
Certs
:
getCertsFromFile
(
t
,
"client-expired"
,
"intermediate"
),
ExpectOK
:
false
,
ExpectErr
:
true
,
},
}
for
k
,
testCase
:=
range
testCases
{
req
,
_
:=
http
.
NewRequest
(
"GET"
,
"/"
,
nil
)
if
!
testCase
.
Insecure
{
req
.
TLS
=
&
tls
.
ConnectionState
{
PeerCertificates
:
testCase
.
Certs
}
}
authCall
:=
false
auth
:=
authenticator
.
RequestFunc
(
func
(
req
*
http
.
Request
)
(
user
.
Info
,
bool
,
error
)
{
authCall
=
true
return
&
user
.
DefaultInfo
{
Name
:
"innerauth"
},
true
,
nil
})
a
:=
NewVerifier
(
testCase
.
Opts
,
auth
,
testCase
.
AllowedCNs
)
user
,
ok
,
err
:=
a
.
AuthenticateRequest
(
req
)
if
testCase
.
ExpectErr
&&
err
==
nil
{
t
.
Errorf
(
"%s: Expected error, got none"
,
k
)
continue
}
if
!
testCase
.
ExpectErr
&&
err
!=
nil
{
t
.
Errorf
(
"%s: Got unexpected error: %v"
,
k
,
err
)
continue
}
if
testCase
.
ExpectOK
!=
ok
{
t
.
Errorf
(
"%s: Expected ok=%v, got %v"
,
k
,
testCase
.
ExpectOK
,
ok
)
continue
}
if
testCase
.
ExpectOK
{
if
!
authCall
{
t
.
Errorf
(
"%s: Expected inner auth called, wasn't"
,
k
)
continue
}
if
"innerauth"
!=
user
.
GetName
()
{
t
.
Errorf
(
"%s: Expected user.name=%v, got %v"
,
k
,
"innerauth"
,
user
.
GetName
())
continue
}
}
else
{
if
authCall
{
t
.
Errorf
(
"%s: Expected inner auth not to be called, was"
,
k
)
continue
}
}
}
}
func
getDefaultVerifyOptions
(
t
*
testing
.
T
)
x509
.
VerifyOptions
{
options
:=
DefaultVerifyOptions
()
options
.
Roots
=
getRootCertPool
(
t
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment