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
e3278d96
Commit
e3278d96
authored
Aug 25, 2016
by
Ilya Dmitrichenko
Committed by
Devan Goodwin
Sep 15, 2016
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Refactor and provide JSON file loaders for endpoints and tokens
parent
d17a236a
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
113 additions
and
79 deletions
+113
-79
kubediscovery.go
cmd/kubediscovery/kubediscovery.go
+16
-12
handlers.go
pkg/kubediscovery/handlers.go
+93
-62
model.go
pkg/kubediscovery/model.go
+4
-5
No files found.
cmd/kubediscovery/kubediscovery.go
View file @
e3278d96
...
...
@@ -21,19 +21,23 @@ import (
)
func
main
()
{
// Make sure the CA cert for the cluster exists and is readable.
// We are expecting a base64 encoded version of the cert PEM as this is how
// the cert would most likely be provided via kubernetes secrets.
if
_
,
err
:=
os
.
Stat
(
kd
.
CAPath
);
os
.
IsNotExist
(
err
)
{
log
.
Fatalf
(
"CA does not exist: %s"
,
kd
.
CAPath
)
}
// Test read permissions
file
,
err
:=
os
.
Open
(
kd
.
CAPath
)
if
err
!=
nil
{
log
.
Fatalf
(
"ERROR: Unable to read %s"
,
kd
.
CAPath
)
// Make sure we can load critical files, and be nice to the user by
// printing descriptive error message when we fail.
for
desc
,
path
:=
range
map
[
string
]
string
{
"root CA certificate"
:
kd
.
CAPath
,
"token map file"
:
kd
.
TokenMapPath
,
"list of API endpoints"
:
kd
.
EndpointListPath
,
}
{
if
_
,
err
:=
os
.
Stat
(
path
);
os
.
IsNotExist
(
err
)
{
log
.
Fatalf
(
"%s does not exist: %s"
,
desc
,
path
)
}
// Test read permissions
file
,
err
:=
os
.
Open
(
path
)
if
err
!=
nil
{
log
.
Fatalf
(
"Unable to open %s (%q [%s])"
,
desc
,
path
,
err
)
}
file
.
Close
()
}
file
.
Close
()
router
:=
kd
.
NewRouter
()
log
.
Printf
(
"Listening for requests on port 9898."
)
...
...
pkg/kubediscovery/handlers.go
View file @
e3278d96
...
...
@@ -14,45 +14,23 @@ package kubediscovery
import
(
"encoding/base64"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"log"
"net/http"
"os"
"github.com/square/go-jose"
)
// TODO: Just using a hardcoded token for now.
const
tempTokenId
string
=
"TOKENID"
const
tempToken
string
=
"EF1BA4F26DDA9FE2"
const
secretPath
=
"/tmp/secret"
// CAPath is the expected location of our cluster's CA to be distributed to
// clients looking to connect. Because we expect to use kubernetes secrets
// for the time being, this file is expected to be a base64 encoded version
// of the normal cert PEM.
const
CAPath
=
"/tmp/secret/ca.pem"
// tokenLoader is an interface for abstracting how we validate
// token IDs and lookup their corresponding token.
type
tokenLoader
interface
{
// Lookup returns the token for a given token ID, or an error if the token ID
// does not exist. Both token and it's ID are expected to be hex encoded strings.
Lookup
(
tokenId
string
)
(
string
,
error
)
}
type
hardcodedTokenLoader
struct
{
}
func
(
tl
*
hardcodedTokenLoader
)
Lookup
(
tokenId
string
)
(
string
,
error
)
{
if
tokenId
==
tempTokenId
{
return
tempToken
,
nil
}
return
""
,
errors
.
New
(
fmt
.
Sprintf
(
"invalid token: %s"
,
tokenId
))
}
const
CAPath
=
secretPath
+
"/ca.pem"
// caLoader is an interface for abstracting how we load the CA certificates
// for the cluster.
...
...
@@ -63,42 +41,94 @@ type caLoader interface {
// fsCALoader is a caLoader for loading the PEM encoded CA from
// /tmp/secret/ca.pem.
type
fsCALoader
struct
{
certData
string
}
func
(
cl
*
fsCALoader
)
LoadPEM
()
(
string
,
error
)
{
file
,
err
:=
os
.
Open
(
CAPath
)
if
err
!=
nil
{
return
""
,
err
if
cl
.
certData
!=
""
{
data
,
err
:=
ioutil
.
ReadFile
(
CAPath
)
if
err
!=
nil
{
return
""
,
err
}
cl
.
certData
=
base64
.
StdEncoding
.
EncodeToString
(
data
)
}
data
,
err
:=
ioutil
.
ReadAll
(
file
)
if
err
!=
nil
{
return
""
,
err
return
cl
.
certData
,
nil
}
const
TokenMapPath
=
secretPath
+
"/token-map.json"
const
EndpointListPath
=
secretPath
+
"/endpoint-list.json"
// tokenLoader is an interface for abstracting how we validate
// token IDs and lookup their corresponding token.
type
tokenLoader
interface
{
// Lookup returns the token for a given token ID, or an error if the token ID
// does not exist. Both token and it's ID are expected be strings.
LoadAndLookup
(
tokenID
string
)
(
string
,
error
)
}
type
jsonFileTokenLoader
struct
{
tokenMap
map
[
string
]
string
}
func
(
tl
*
jsonFileTokenLoader
)
LoadAndLookup
(
tokenID
string
)
(
string
,
error
)
{
if
len
(
tl
.
tokenMap
)
==
0
{
data
,
err
:=
ioutil
.
ReadFile
(
TokenMapPath
)
if
err
!=
nil
{
return
""
,
err
}
if
err
:=
json
.
Unmarshal
(
data
,
&
tl
.
tokenMap
);
err
!=
nil
{
return
""
,
err
}
}
if
val
,
ok
:=
tl
.
tokenMap
[
tokenID
];
ok
{
return
val
,
nil
}
return
""
,
errors
.
New
(
fmt
.
Sprintf
(
"invalid token: %s"
,
tokenID
))
}
return
string
(
data
),
nil
type
endpointsLoader
interface
{
LoadList
()
([]
string
,
error
)
}
type
jsonFileEnpointsLoader
struct
{
endpoints
[]
string
}
func
(
el
*
jsonFileEnpointsLoader
)
LoadList
()
([]
string
,
error
)
{
if
len
(
el
.
endpoints
)
==
0
{
data
,
err
:=
ioutil
.
ReadFile
(
EndpointListPath
)
if
err
!=
nil
{
return
nil
,
err
}
if
err
:=
json
.
Unmarshal
(
data
,
&
el
.
endpoints
);
err
!=
nil
{
return
nil
,
err
}
}
return
el
.
endpoints
,
nil
}
// ClusterInfoHandler implements the http.ServeHTTP method and allows us to
// mock out portions of the request handler in tests.
type
ClusterInfoHandler
struct
{
tokenLoader
tokenLoader
caLoader
caLoader
tokenLoader
tokenLoader
caLoader
caLoader
endpointsLoader
endpointsLoader
}
func
NewClusterInfoHandler
()
*
ClusterInfoHandler
{
tl
:=
hardcodedTokenLoader
{}
cl
:=
fsCALoader
{}
return
&
ClusterInfoHandler
{
tokenLoader
:
&
tl
,
caLoader
:
&
cl
,
tokenLoader
:
&
jsonFileTokenLoader
{},
caLoader
:
&
fsCALoader
{},
endpointsLoader
:
&
jsonFileEnpointsLoader
{},
}
}
func
(
cih
*
ClusterInfoHandler
)
ServeHTTP
(
resp
http
.
ResponseWriter
,
req
*
http
.
Request
)
{
tokenI
d
:=
req
.
FormValue
(
"token-id"
)
log
.
Printf
(
"Got token ID: %s"
,
tokenI
d
)
token
,
err
:=
cih
.
tokenLoader
.
Lo
okup
(
tokenId
)
tokenI
D
:=
req
.
FormValue
(
"token-id"
)
log
.
Printf
(
"Got token ID: %s"
,
tokenI
D
)
token
,
err
:=
cih
.
tokenLoader
.
Lo
adAndLookup
(
tokenID
)
if
err
!=
nil
{
log
.
Printf
(
"Invalid token: %s"
,
err
)
http
.
Error
(
resp
,
"Forbidden"
,
http
.
StatusForbidden
)
...
...
@@ -106,32 +136,42 @@ func (cih *ClusterInfoHandler) ServeHTTP(resp http.ResponseWriter, req *http.Req
}
log
.
Printf
(
"Loaded token: %s"
,
token
)
// TODO probably should not leak server-side errors to the client
caPEM
,
err
:=
cih
.
caLoader
.
LoadPEM
()
caB64
:=
base64
.
StdEncoding
.
EncodeToString
([]
byte
(
caPEM
))
if
err
!=
nil
{
err
=
fmt
.
Errorf
(
"Error loading root CA certificate data: %s"
,
err
)
log
.
Println
(
err
)
http
.
Error
(
resp
,
err
.
Error
(),
http
.
StatusInternalServerError
)
return
}
endpoints
,
err
:=
cih
.
endpointsLoader
.
LoadList
()
if
err
!=
nil
{
http
.
Error
(
resp
,
"Error encoding CA"
,
http
.
StatusInternalServerError
)
err
=
fmt
.
Errorf
(
"Error loading list of API endpoints: %s"
,
err
)
log
.
Println
(
err
)
http
.
Error
(
resp
,
err
.
Error
(),
http
.
StatusInternalServerError
)
return
}
clusterInfo
:=
ClusterInfo
{
Type
:
"ClusterInfo"
,
Version
:
"v1"
,
RootCertificates
:
caB64
,
CertificateAuthorities
:
[]
string
{
caPEM
},
Endpoints
:
endpoints
,
}
// Instantiate an signer using HMAC-SHA256.
hmacTestKey
:=
fromHexBytes
(
token
)
signer
,
err
:=
jose
.
NewSigner
(
jose
.
HS256
,
hmacTestKey
)
signer
,
err
:=
jose
.
NewSigner
(
jose
.
HS256
,
[]
byte
(
token
))
if
err
!=
nil
{
http
.
Error
(
resp
,
fmt
.
Sprintf
(
"Error creating JWS signer: %s"
,
err
),
http
.
StatusInternalServerError
)
err
=
fmt
.
Errorf
(
"Error creating JWS signer: %s"
,
err
)
log
.
Println
(
err
)
http
.
Error
(
resp
,
err
.
Error
(),
http
.
StatusInternalServerError
)
return
}
payload
,
err
:=
json
.
Marshal
(
clusterInfo
)
if
err
!=
nil
{
http
.
Error
(
resp
,
fmt
.
Sprintf
(
"Error serializing clusterInfo to JSON: %s"
,
err
),
http
.
StatusInternalServerError
)
err
=
fmt
.
Errorf
(
"Error serializing clusterInfo to JSON: %s"
,
err
)
log
.
Println
(
err
)
http
.
Error
(
resp
,
err
.
Error
(),
http
.
StatusInternalServerError
)
return
}
...
...
@@ -140,8 +180,9 @@ func (cih *ClusterInfoHandler) ServeHTTP(resp http.ResponseWriter, req *http.Req
// indicate a problem in an underlying cryptographic primitive.
jws
,
err
:=
signer
.
Sign
(
payload
)
if
err
!=
nil
{
http
.
Error
(
resp
,
fmt
.
Sprintf
(
"Error signing clusterInfo to JSON: %s"
,
err
),
http
.
StatusInternalServerError
)
err
=
fmt
.
Errorf
(
"Error signing clusterInfo with JWS: %s"
,
err
)
log
.
Println
(
err
)
http
.
Error
(
resp
,
err
.
Error
(),
http
.
StatusInternalServerError
)
return
}
...
...
@@ -153,13 +194,3 @@ func (cih *ClusterInfoHandler) ServeHTTP(resp http.ResponseWriter, req *http.Req
resp
.
Write
([]
byte
(
serialized
))
}
// TODO: Move into test package
// TODO: Should we use base64 instead?
func
fromHexBytes
(
base16
string
)
[]
byte
{
val
,
err
:=
hex
.
DecodeString
(
base16
)
if
err
!=
nil
{
panic
(
fmt
.
Sprintf
(
"Invalid test data: %s"
,
err
))
}
return
val
}
pkg/kubediscovery/model.go
View file @
e3278d96
...
...
@@ -12,10 +12,9 @@ limitations under the License.
*/
package
kubediscovery
// TODO: Sync with kubeadm api type
type
ClusterInfo
struct
{
Type
string
Version
string
RootCertificates
string
`json:"rootCertificates
"`
// TODO: ClusterID, Endpoints
// TODO Kind, apiVersion
// TODO clusterId, fetchedTime, expiredTime
CertificateAuthorities
[]
string
`json:"certificateAuthorities,omitempty
"`
Endpoints
[]
string
`json:"endpoints,omitempty"`
}
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