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
0e210807
Commit
0e210807
authored
Dec 24, 2022
by
Brad Davidson
Committed by
Brad Davidson
Feb 10, 2023
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Ensure that node exists when using node auth
Signed-off-by:
Brad Davidson
<
brad.davidson@rancher.com
>
(cherry picked from commit
87f9c4ab
)
parent
fe1be2b3
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
77 additions
and
33 deletions
+77
-33
router.go
pkg/server/router.go
+77
-33
No files found.
pkg/server/router.go
View file @
0e210807
...
@@ -32,13 +32,19 @@ import (
...
@@ -32,13 +32,19 @@ import (
"k8s.io/apimachinery/pkg/util/json"
"k8s.io/apimachinery/pkg/util/json"
"k8s.io/apiserver/pkg/authentication/user"
"k8s.io/apiserver/pkg/authentication/user"
"k8s.io/apiserver/pkg/endpoints/handlers/responsewriters"
"k8s.io/apiserver/pkg/endpoints/handlers/responsewriters"
"k8s.io/apiserver/pkg/endpoints/request"
bootstrapapi
"k8s.io/cluster-bootstrap/token/api"
bootstrapapi
"k8s.io/cluster-bootstrap/token/api"
"k8s.io/kubernetes/pkg/auth/nodeidentifier"
)
)
const
(
const
(
staticURL
=
"/static/"
staticURL
=
"/static/"
)
)
var
(
identifier
=
nodeidentifier
.
NewDefaultNodeIdentifier
()
)
func
router
(
ctx
context
.
Context
,
config
*
Config
,
cfg
*
cmds
.
Server
)
http
.
Handler
{
func
router
(
ctx
context
.
Context
,
config
*
Config
,
cfg
*
cmds
.
Server
)
http
.
Handler
{
serverConfig
:=
&
config
.
ControlConfig
serverConfig
:=
&
config
.
ControlConfig
nodeAuth
:=
passwordBootstrap
(
ctx
,
config
)
nodeAuth
:=
passwordBootstrap
(
ctx
,
config
)
...
@@ -143,18 +149,27 @@ func cacerts(serverCA string) http.Handler {
...
@@ -143,18 +149,27 @@ func cacerts(serverCA string) http.Handler {
})
})
}
}
func
getNodeInfo
(
req
*
http
.
Request
)
(
string
,
string
,
error
)
{
func
getNodeInfo
(
req
*
http
.
Request
)
(
*
nodeInfo
,
error
)
{
user
,
ok
:=
request
.
UserFrom
(
req
.
Context
())
if
!
ok
{
return
nil
,
errors
.
New
(
"auth user not set"
)
}
nodeName
:=
req
.
Header
.
Get
(
version
.
Program
+
"-Node-Name"
)
nodeName
:=
req
.
Header
.
Get
(
version
.
Program
+
"-Node-Name"
)
if
nodeName
==
""
{
if
nodeName
==
""
{
return
""
,
""
,
errors
.
New
(
"node name not set"
)
return
nil
,
errors
.
New
(
"node name not set"
)
}
}
nodePassword
:=
req
.
Header
.
Get
(
version
.
Program
+
"-Node-Password"
)
nodePassword
:=
req
.
Header
.
Get
(
version
.
Program
+
"-Node-Password"
)
if
nodePassword
==
""
{
if
nodePassword
==
""
{
return
""
,
""
,
errors
.
New
(
"node password not set"
)
return
nil
,
errors
.
New
(
"node password not set"
)
}
}
return
strings
.
ToLower
(
nodeName
),
nodePassword
,
nil
return
&
nodeInfo
{
Name
:
strings
.
ToLower
(
nodeName
),
Password
:
nodePassword
,
User
:
user
,
},
nil
}
}
func
getCACertAndKeys
(
caCertFile
,
caKeyFile
,
signingKeyFile
string
)
([]
*
x509
.
Certificate
,
crypto
.
Signer
,
crypto
.
Signer
,
error
)
{
func
getCACertAndKeys
(
caCertFile
,
caKeyFile
,
signingKeyFile
string
)
([]
*
x509
.
Certificate
,
crypto
.
Signer
,
crypto
.
Signer
,
error
)
{
...
@@ -398,43 +413,63 @@ func sendError(err error, resp http.ResponseWriter, status ...int) {
...
@@ -398,43 +413,63 @@ func sendError(err error, resp http.ResponseWriter, status ...int) {
// nodePassBootstrapper returns a node name, or http error code and error
// nodePassBootstrapper returns a node name, or http error code and error
type
nodePassBootstrapper
func
(
req
*
http
.
Request
)
(
string
,
int
,
error
)
type
nodePassBootstrapper
func
(
req
*
http
.
Request
)
(
string
,
int
,
error
)
// nodeInfo contains information on the requesting node, derived from auth creds
// and request headers.
type
nodeInfo
struct
{
Name
string
Password
string
User
user
.
Info
}
func
passwordBootstrap
(
ctx
context
.
Context
,
config
*
Config
)
nodePassBootstrapper
{
func
passwordBootstrap
(
ctx
context
.
Context
,
config
*
Config
)
nodePassBootstrapper
{
runtime
:=
config
.
ControlConfig
.
Runtime
runtime
:=
config
.
ControlConfig
.
Runtime
deferredNodes
:=
map
[
string
]
bool
{}
deferredNodes
:=
map
[
string
]
bool
{}
var
secretClient
coreclient
.
SecretClient
var
secretClient
coreclient
.
SecretClient
var
nodeClient
coreclient
.
NodeClient
var
mu
sync
.
Mutex
var
mu
sync
.
Mutex
return
nodePassBootstrapper
(
func
(
req
*
http
.
Request
)
(
string
,
int
,
error
)
{
return
nodePassBootstrapper
(
func
(
req
*
http
.
Request
)
(
string
,
int
,
error
)
{
node
Name
,
nodePassword
,
err
:=
getNodeInfo
(
req
)
node
,
err
:=
getNodeInfo
(
req
)
if
err
!=
nil
{
if
err
!=
nil
{
return
""
,
http
.
StatusBadRequest
,
err
return
""
,
http
.
StatusBadRequest
,
err
}
}
if
secretClient
==
nil
{
nodeName
,
isNodeAuth
:=
identifier
.
NodeIdentity
(
node
.
User
)
if
isNodeAuth
&&
nodeName
!=
node
.
Name
{
return
""
,
http
.
StatusBadRequest
,
errors
.
New
(
"header node name does not match auth node name"
)
}
if
secretClient
==
nil
||
nodeClient
==
nil
{
if
runtime
.
Core
!=
nil
{
if
runtime
.
Core
!=
nil
{
// initialize the client if we can
// initialize the client if we can
secretClient
=
runtime
.
Core
.
Core
()
.
V1
()
.
Secret
()
secretClient
=
runtime
.
Core
.
Core
()
.
V1
()
.
Secret
()
}
else
if
nodeName
==
os
.
Getenv
(
"NODE_NAME"
)
{
nodeClient
=
runtime
.
Core
.
Core
()
.
V1
()
.
Node
()
// or verify the password locally and ensure a secret later
}
else
if
node
.
Name
==
os
.
Getenv
(
"NODE_NAME"
)
{
return
verifyLocalPassword
(
ctx
,
config
,
&
mu
,
deferredNodes
,
nodeName
,
nodePassword
)
// If we're verifying our own password, verify it locally and ensure a secret later.
}
else
if
config
.
ControlConfig
.
DisableAPIServer
{
return
verifyLocalPassword
(
ctx
,
config
,
&
mu
,
deferredNodes
,
node
)
// or defer node password verification until an apiserver joins the cluster
}
else
if
config
.
ControlConfig
.
DisableAPIServer
&&
!
isNodeAuth
{
return
verifyRemotePassword
(
ctx
,
config
,
&
mu
,
deferredNodes
,
nodeName
,
nodePassword
)
// If we're running on an etcd-only node, and the request didn't use Node Identity auth,
// defer node password verification until an apiserver joins the cluster.
return
verifyRemotePassword
(
ctx
,
config
,
&
mu
,
deferredNodes
,
node
)
}
else
{
}
else
{
//
or reject the request until the core is ready
//
Otherwise, reject the request until the core is ready.
return
""
,
http
.
StatusServiceUnavailable
,
errors
.
New
(
"runtime core not ready"
)
return
""
,
http
.
StatusServiceUnavailable
,
errors
.
New
(
"runtime core not ready"
)
}
}
}
}
if
err
:=
nodepassword
.
Ensure
(
secretClient
,
nodeName
,
nodePassword
);
err
!=
nil
{
if
err
:=
verifyNode
(
ctx
,
nodeClient
,
node
);
err
!=
nil
{
return
""
,
http
.
StatusUnauthorized
,
err
}
if
err
:=
nodepassword
.
Ensure
(
secretClient
,
node
.
Name
,
node
.
Password
);
err
!=
nil
{
return
""
,
http
.
StatusForbidden
,
err
return
""
,
http
.
StatusForbidden
,
err
}
}
return
nodeName
,
http
.
StatusOK
,
nil
return
node
.
Name
,
http
.
StatusOK
,
nil
})
})
}
}
func
verifyLocalPassword
(
ctx
context
.
Context
,
config
*
Config
,
mu
*
sync
.
Mutex
,
deferredNodes
map
[
string
]
bool
,
node
Name
,
nodePassword
string
)
(
string
,
int
,
error
)
{
func
verifyLocalPassword
(
ctx
context
.
Context
,
config
*
Config
,
mu
*
sync
.
Mutex
,
deferredNodes
map
[
string
]
bool
,
node
*
nodeInfo
)
(
string
,
int
,
error
)
{
// use same password file location that the agent creates
// use same password file location that the agent creates
nodePasswordRoot
:=
"/"
nodePasswordRoot
:=
"/"
if
config
.
ControlConfig
.
Rootless
{
if
config
.
ControlConfig
.
Rootless
{
...
@@ -449,36 +484,45 @@ func verifyLocalPassword(ctx context.Context, config *Config, mu *sync.Mutex, de
...
@@ -449,36 +484,45 @@ func verifyLocalPassword(ctx context.Context, config *Config, mu *sync.Mutex, de
}
}
password
:=
strings
.
TrimSpace
(
string
(
passBytes
))
password
:=
strings
.
TrimSpace
(
string
(
passBytes
))
if
password
!=
nodePassword
{
if
password
!=
node
.
Password
{
return
""
,
http
.
StatusForbidden
,
errors
.
Wrapf
(
err
,
"unable to verify local password for node '%s'"
,
nodeName
)
return
""
,
http
.
StatusForbidden
,
errors
.
Wrapf
(
err
,
"unable to verify local password for node '%s'"
,
node
.
Name
)
}
}
mu
.
Lock
()
mu
.
Lock
()
defer
mu
.
Unlock
()
defer
mu
.
Unlock
()
if
_
,
ok
:=
deferredNodes
[
nodeName
];
!
ok
{
if
_
,
ok
:=
deferredNodes
[
node
.
Name
];
!
ok
{
deferredNodes
[
nodeName
]
=
true
deferredNodes
[
node
.
Name
]
=
true
go
ensureSecret
(
ctx
,
config
,
node
Name
,
nodePassword
)
go
ensureSecret
(
ctx
,
config
,
node
)
logrus
.
Debugf
(
"Password verified locally for node '%s'"
,
nodeName
)
logrus
.
Debugf
(
"Password verified locally for node '%s'"
,
node
.
Name
)
}
}
return
nodeName
,
http
.
StatusOK
,
nil
return
node
.
Name
,
http
.
StatusOK
,
nil
}
}
func
verifyRemotePassword
(
ctx
context
.
Context
,
config
*
Config
,
mu
*
sync
.
Mutex
,
deferredNodes
map
[
string
]
bool
,
node
Name
,
nodePassword
string
)
(
string
,
int
,
error
)
{
func
verifyRemotePassword
(
ctx
context
.
Context
,
config
*
Config
,
mu
*
sync
.
Mutex
,
deferredNodes
map
[
string
]
bool
,
node
*
nodeInfo
)
(
string
,
int
,
error
)
{
mu
.
Lock
()
mu
.
Lock
()
defer
mu
.
Unlock
()
defer
mu
.
Unlock
()
if
_
,
ok
:=
deferredNodes
[
nodeName
];
!
ok
{
if
_
,
ok
:=
deferredNodes
[
node
.
Name
];
!
ok
{
deferredNodes
[
nodeName
]
=
true
deferredNodes
[
node
.
Name
]
=
true
go
ensureSecret
(
ctx
,
config
,
node
Name
,
nodePassword
)
go
ensureSecret
(
ctx
,
config
,
node
)
logrus
.
Debugf
(
"Password verification deferred for node '%s'"
,
nodeName
)
logrus
.
Debugf
(
"Password verification deferred for node '%s'"
,
node
.
Name
)
}
}
return
nodeName
,
http
.
StatusOK
,
nil
return
node
.
Name
,
http
.
StatusOK
,
nil
}
func
verifyNode
(
ctx
context
.
Context
,
nodeClient
coreclient
.
NodeClient
,
node
*
nodeInfo
)
error
{
if
nodeName
,
isNodeAuth
:=
identifier
.
NodeIdentity
(
node
.
User
);
isNodeAuth
{
if
_
,
err
:=
nodeClient
.
Get
(
nodeName
,
metav1
.
GetOptions
{});
err
!=
nil
{
return
errors
.
Wrap
(
err
,
"unable to verify node identity"
)
}
}
return
nil
}
}
func
ensureSecret
(
ctx
context
.
Context
,
config
*
Config
,
node
Name
,
nodePassword
string
)
{
func
ensureSecret
(
ctx
context
.
Context
,
config
*
Config
,
node
*
nodeInfo
)
{
runtime
:=
config
.
ControlConfig
.
Runtime
runtime
:=
config
.
ControlConfig
.
Runtime
for
{
for
{
select
{
select
{
...
@@ -486,10 +530,10 @@ func ensureSecret(ctx context.Context, config *Config, nodeName, nodePassword st
...
@@ -486,10 +530,10 @@ func ensureSecret(ctx context.Context, config *Config, nodeName, nodePassword st
return
return
case
<-
time
.
After
(
1
*
time
.
Second
)
:
case
<-
time
.
After
(
1
*
time
.
Second
)
:
if
runtime
.
Core
!=
nil
{
if
runtime
.
Core
!=
nil
{
logrus
.
Debugf
(
"Runtime core has become available, ensuring password secret for node '%s'"
,
nodeName
)
logrus
.
Debugf
(
"Runtime core has become available, ensuring password secret for node '%s'"
,
node
.
Name
)
secretClient
:=
runtime
.
Core
.
Core
()
.
V1
()
.
Secret
()
secretClient
:=
runtime
.
Core
.
Core
()
.
V1
()
.
Secret
()
if
err
:=
nodepassword
.
Ensure
(
secretClient
,
node
Name
,
node
Password
);
err
!=
nil
{
if
err
:=
nodepassword
.
Ensure
(
secretClient
,
node
.
Name
,
node
.
Password
);
err
!=
nil
{
logrus
.
Warnf
(
"Error ensuring node password secret for pre-validated node '%s': %v"
,
nodeName
,
err
)
logrus
.
Warnf
(
"Error ensuring node password secret for pre-validated node '%s': %v"
,
node
.
Name
,
err
)
}
}
return
return
}
}
...
...
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