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
3c92eb75
Unverified
Commit
3c92eb75
authored
Oct 04, 2016
by
Jordan Liggitt
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Enable service account signing key rotation
parent
96fde0fe
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
82 additions
and
39 deletions
+82
-39
options.go
cmd/kube-apiserver/app/options/options.go
+5
-4
server.go
cmd/kube-apiserver/app/server.go
+4
-4
authn.go
pkg/apiserver/authenticator/authn.go
+13
-9
jwt.go
pkg/serviceaccount/jwt.go
+41
-17
jwt_test.go
pkg/serviceaccount/jwt_test.go
+19
-5
No files found.
cmd/kube-apiserver/app/options/options.go
View file @
3c92eb75
...
...
@@ -37,7 +37,7 @@ type APIServer struct {
MaxConnectionBytesPerSec
int64
SSHKeyfile
string
SSHUser
string
ServiceAccountKeyFile
string
ServiceAccountKeyFile
s
[]
string
ServiceAccountLookup
bool
WebhookTokenAuthnConfigFile
string
WebhookTokenAuthnCacheTTL
time
.
Duration
...
...
@@ -70,9 +70,10 @@ func (s *APIServer) AddFlags(fs *pflag.FlagSet) {
fs
.
DurationVar
(
&
s
.
EventTTL
,
"event-ttl"
,
s
.
EventTTL
,
"Amount of time to retain events. Default is 1h."
)
fs
.
StringVar
(
&
s
.
ServiceAccountKeyFile
,
"service-account-key-file"
,
s
.
ServiceAccountKeyFile
,
""
+
"File containing PEM-encoded x509 RSA or ECDSA private or public key, used to verify "
+
"ServiceAccount tokens. If unspecified, --tls-private-key-file is used."
)
fs
.
StringArrayVar
(
&
s
.
ServiceAccountKeyFiles
,
"service-account-key-file"
,
s
.
ServiceAccountKeyFiles
,
""
+
"File containing PEM-encoded x509 RSA or ECDSA private or public keys, used to verify "
+
"ServiceAccount tokens. If unspecified, --tls-private-key-file is used. "
+
"The specified file can contain multiple keys, and the flag can be specified multiple times with different files."
)
fs
.
BoolVar
(
&
s
.
ServiceAccountLookup
,
"service-account-lookup"
,
s
.
ServiceAccountLookup
,
"If true, validate ServiceAccount tokens exist in etcd as part of authentication."
)
...
...
cmd/kube-apiserver/app/server.go
View file @
3c92eb75
...
...
@@ -181,11 +181,11 @@ func Run(s *options.APIServer) error {
}
// Default to the private server key for service account token signing
if
s
.
ServiceAccountKeyFile
==
""
&&
s
.
TLSPrivateKeyFile
!=
""
{
if
len
(
s
.
ServiceAccountKeyFiles
)
==
0
&&
s
.
TLSPrivateKeyFile
!=
""
{
if
authenticator
.
IsValidServiceAccountKeyFile
(
s
.
TLSPrivateKeyFile
)
{
s
.
ServiceAccountKeyFile
=
s
.
TLSPrivateKeyFile
s
.
ServiceAccountKeyFile
s
=
[]
string
{
s
.
TLSPrivateKeyFile
}
}
else
{
glog
.
Warning
(
"No
RSA
key provided, service account token authentication disabled"
)
glog
.
Warning
(
"No
TLS
key provided, service account token authentication disabled"
)
}
}
...
...
@@ -211,7 +211,7 @@ func Run(s *options.APIServer) error {
OIDCCAFile
:
s
.
OIDCCAFile
,
OIDCUsernameClaim
:
s
.
OIDCUsernameClaim
,
OIDCGroupsClaim
:
s
.
OIDCGroupsClaim
,
ServiceAccountKeyFile
:
s
.
ServiceAccountKeyFile
,
ServiceAccountKeyFile
s
:
s
.
ServiceAccountKeyFiles
,
ServiceAccountLookup
:
s
.
ServiceAccountLookup
,
ServiceAccountTokenGetter
:
serviceAccountGetter
,
KeystoneURL
:
s
.
KeystoneURL
,
...
...
pkg/apiserver/authenticator/authn.go
View file @
3c92eb75
...
...
@@ -48,7 +48,7 @@ type AuthenticatorConfig struct {
OIDCCAFile
string
OIDCUsernameClaim
string
OIDCGroupsClaim
string
ServiceAccountKeyFile
string
ServiceAccountKeyFile
s
[]
string
ServiceAccountLookup
bool
ServiceAccountTokenGetter
serviceaccount
.
ServiceAccountTokenGetter
KeystoneURL
string
...
...
@@ -94,8 +94,8 @@ func New(config AuthenticatorConfig) (authenticator.Request, error) {
}
authenticators
=
append
(
authenticators
,
tokenAuth
)
}
if
len
(
config
.
ServiceAccountKeyFile
)
>
0
{
serviceAccountAuth
,
err
:=
newServiceAccountAuthenticator
(
config
.
ServiceAccountKeyFile
,
config
.
ServiceAccountLookup
,
config
.
ServiceAccountTokenGetter
)
if
len
(
config
.
ServiceAccountKeyFile
s
)
>
0
{
serviceAccountAuth
,
err
:=
newServiceAccountAuthenticator
(
config
.
ServiceAccountKeyFile
s
,
config
.
ServiceAccountLookup
,
config
.
ServiceAccountTokenGetter
)
if
err
!=
nil
{
return
nil
,
err
}
...
...
@@ -152,7 +152,7 @@ func New(config AuthenticatorConfig) (authenticator.Request, error) {
// IsValidServiceAccountKeyFile returns true if a valid public RSA key can be read from the given file
func
IsValidServiceAccountKeyFile
(
file
string
)
bool
{
_
,
err
:=
serviceaccount
.
ReadPublicKey
(
file
)
_
,
err
:=
serviceaccount
.
ReadPublicKey
s
(
file
)
return
err
==
nil
}
...
...
@@ -198,13 +198,17 @@ func newAuthenticatorFromOIDCIssuerURL(issuerURL, clientID, caFile, usernameClai
}
// newServiceAccountAuthenticator returns an authenticator.Request or an error
func
newServiceAccountAuthenticator
(
keyfile
string
,
lookup
bool
,
serviceAccountGetter
serviceaccount
.
ServiceAccountTokenGetter
)
(
authenticator
.
Request
,
error
)
{
publicKey
,
err
:=
serviceaccount
.
ReadPublicKey
(
keyfile
)
if
err
!=
nil
{
return
nil
,
err
func
newServiceAccountAuthenticator
(
keyfiles
[]
string
,
lookup
bool
,
serviceAccountGetter
serviceaccount
.
ServiceAccountTokenGetter
)
(
authenticator
.
Request
,
error
)
{
allPublicKeys
:=
[]
interface
{}{}
for
_
,
keyfile
:=
range
keyfiles
{
publicKeys
,
err
:=
serviceaccount
.
ReadPublicKeys
(
keyfile
)
if
err
!=
nil
{
return
nil
,
err
}
allPublicKeys
=
append
(
allPublicKeys
,
publicKeys
...
)
}
tokenAuthenticator
:=
serviceaccount
.
JWTTokenAuthenticator
(
[]
interface
{}{
publicKey
}
,
lookup
,
serviceAccountGetter
)
tokenAuthenticator
:=
serviceaccount
.
JWTTokenAuthenticator
(
allPublicKeys
,
lookup
,
serviceAccountGetter
)
return
bearertoken
.
New
(
tokenAuthenticator
),
nil
}
...
...
pkg/serviceaccount/jwt.go
View file @
3c92eb75
...
...
@@ -21,6 +21,7 @@ import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rsa"
"encoding/pem"
"errors"
"fmt"
"io/ioutil"
...
...
@@ -80,37 +81,60 @@ func ReadPrivateKeyFromPEM(data []byte) (interface{}, error) {
return
nil
,
fmt
.
Errorf
(
"data does not contain a valid RSA or ECDSA private key"
)
}
// ReadPublicKey
is a helper function for reading an
rsa.PublicKey or ecdsa.PublicKey from a PEM-encoded file.
// ReadPublicKey
s is a helper function for reading an array of
rsa.PublicKey or ecdsa.PublicKey from a PEM-encoded file.
// Reads public keys from both public and private key files.
func
ReadPublicKey
(
file
string
)
(
interface
{},
error
)
{
func
ReadPublicKey
s
(
file
string
)
([]
interface
{},
error
)
{
data
,
err
:=
ioutil
.
ReadFile
(
file
)
if
err
!=
nil
{
return
nil
,
err
}
key
,
err
:=
ReadPublicKey
FromPEM
(
data
)
key
s
,
err
:=
ReadPublicKeys
FromPEM
(
data
)
if
err
!=
nil
{
return
nil
,
fmt
.
Errorf
(
"error reading public key file %s: %v"
,
file
,
err
)
}
return
key
,
nil
return
key
s
,
nil
}
// ReadPublicKey
FromPEM is a helper function for reading an
rsa.PublicKey or ecdsa.PublicKey from a PEM-encoded byte array.
// ReadPublicKey
sFromPEM is a helper function for reading an array of
rsa.PublicKey or ecdsa.PublicKey from a PEM-encoded byte array.
// Reads public keys from both public and private key files.
func
ReadPublicKeyFromPEM
(
data
[]
byte
)
(
interface
{},
error
)
{
if
privateKey
,
err
:=
jwt
.
ParseRSAPrivateKeyFromPEM
(
data
);
err
==
nil
{
return
&
privateKey
.
PublicKey
,
nil
}
if
publicKey
,
err
:=
jwt
.
ParseRSAPublicKeyFromPEM
(
data
);
err
==
nil
{
return
publicKey
,
nil
}
func
ReadPublicKeysFromPEM
(
data
[]
byte
)
([]
interface
{},
error
)
{
var
block
*
pem
.
Block
keys
:=
[]
interface
{}{}
for
{
// read the next block
block
,
data
=
pem
.
Decode
(
data
)
if
block
==
nil
{
break
}
if
privateKey
,
err
:=
jwt
.
ParseECPrivateKeyFromPEM
(
data
);
err
==
nil
{
return
&
privateKey
.
PublicKey
,
nil
// get PEM bytes for just this block
blockData
:=
pem
.
EncodeToMemory
(
block
)
if
privateKey
,
err
:=
jwt
.
ParseRSAPrivateKeyFromPEM
(
blockData
);
err
==
nil
{
keys
=
append
(
keys
,
&
privateKey
.
PublicKey
)
continue
}
if
publicKey
,
err
:=
jwt
.
ParseRSAPublicKeyFromPEM
(
blockData
);
err
==
nil
{
keys
=
append
(
keys
,
publicKey
)
continue
}
if
privateKey
,
err
:=
jwt
.
ParseECPrivateKeyFromPEM
(
blockData
);
err
==
nil
{
keys
=
append
(
keys
,
&
privateKey
.
PublicKey
)
continue
}
if
publicKey
,
err
:=
jwt
.
ParseECPublicKeyFromPEM
(
blockData
);
err
==
nil
{
keys
=
append
(
keys
,
publicKey
)
continue
}
// tolerate non-key PEM blocks for backwards compatibility
// originally, only the first PEM block was parsed and expected to be a key block
}
if
publicKey
,
err
:=
jwt
.
ParseECPublicKeyFromPEM
(
data
);
err
==
nil
{
return
publicKey
,
nil
if
len
(
keys
)
==
0
{
return
nil
,
fmt
.
Errorf
(
"data does not contain a valid RSA or ECDSA key"
)
}
return
nil
,
fmt
.
Errorf
(
"data does not contain a valid RSA or ECDSA key"
)
return
keys
,
nil
}
// JWTTokenGenerator returns a TokenGenerator that generates signed JWT tokens, using the given privateKey.
...
...
pkg/serviceaccount/jwt_test.go
View file @
3c92eb75
...
...
@@ -98,8 +98,8 @@ func getPrivateKey(data string) interface{} {
}
func
getPublicKey
(
data
string
)
interface
{}
{
key
,
_
:=
serviceaccount
.
ReadPublicKey
FromPEM
([]
byte
(
data
))
return
key
key
s
,
_
:=
serviceaccount
.
ReadPublicKeys
FromPEM
([]
byte
(
data
))
return
key
s
[
0
]
}
func
TestReadPrivateKey
(
t
*
testing
.
T
)
{
f
,
err
:=
ioutil
.
TempFile
(
""
,
""
)
...
...
@@ -123,7 +123,7 @@ func TestReadPrivateKey(t *testing.T) {
}
}
func
TestReadPublicKey
(
t
*
testing
.
T
)
{
func
TestReadPublicKey
s
(
t
*
testing
.
T
)
{
f
,
err
:=
ioutil
.
TempFile
(
""
,
""
)
if
err
!=
nil
{
t
.
Fatalf
(
"error creating tmpfile: %v"
,
err
)
...
...
@@ -133,16 +133,30 @@ func TestReadPublicKey(t *testing.T) {
if
err
:=
ioutil
.
WriteFile
(
f
.
Name
(),
[]
byte
(
rsaPublicKey
),
os
.
FileMode
(
0600
));
err
!=
nil
{
t
.
Fatalf
(
"error writing public key to tmpfile: %v"
,
err
)
}
if
_
,
err
:=
serviceaccount
.
ReadPublicKey
(
f
.
Name
());
err
!=
nil
{
if
keys
,
err
:=
serviceaccount
.
ReadPublicKeys
(
f
.
Name
());
err
!=
nil
{
t
.
Fatalf
(
"error reading RSA public key: %v"
,
err
)
}
else
if
len
(
keys
)
!=
1
{
t
.
Fatalf
(
"expected 1 key, got %d"
,
len
(
keys
))
}
if
err
:=
ioutil
.
WriteFile
(
f
.
Name
(),
[]
byte
(
ecdsaPublicKey
),
os
.
FileMode
(
0600
));
err
!=
nil
{
t
.
Fatalf
(
"error writing public key to tmpfile: %v"
,
err
)
}
if
_
,
err
:=
serviceaccount
.
ReadPublicKey
(
f
.
Name
());
err
!=
nil
{
if
keys
,
err
:=
serviceaccount
.
ReadPublicKeys
(
f
.
Name
());
err
!=
nil
{
t
.
Fatalf
(
"error reading ECDSA public key: %v"
,
err
)
}
else
if
len
(
keys
)
!=
1
{
t
.
Fatalf
(
"expected 1 key, got %d"
,
len
(
keys
))
}
if
err
:=
ioutil
.
WriteFile
(
f
.
Name
(),
[]
byte
(
rsaPublicKey
+
"
\n
"
+
ecdsaPublicKey
),
os
.
FileMode
(
0600
));
err
!=
nil
{
t
.
Fatalf
(
"error writing public key to tmpfile: %v"
,
err
)
}
if
keys
,
err
:=
serviceaccount
.
ReadPublicKeys
(
f
.
Name
());
err
!=
nil
{
t
.
Fatalf
(
"error reading combined RSA/ECDSA public key file: %v"
,
err
)
}
else
if
len
(
keys
)
!=
2
{
t
.
Fatalf
(
"expected 2 keys, got %d"
,
len
(
keys
))
}
}
func
TestTokenGenerateAndValidate
(
t
*
testing
.
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