Skip to content

Commit

Permalink
add revokeNode endpoint in RKS Administration (#23)
Browse files Browse the repository at this point in the history
* add endpoint specification in RKS Administration

Signed-off-by: Céline Nicolas <[email protected]>

* add endpoint specification in RKS Administration

Signed-off-by: Céline Nicolas <[email protected]>

* add revoke node endpoint

Signed-off-by: Céline Nicolas <[email protected]>

* add revokenode endpoint

Signed-off-by: Céline Nicolas <[email protected]>

* improve assert msg in tests

Signed-off-by: Céline Nicolas <[email protected]>

* Update pkg/api/admin/administration.go

Co-authored-by: Glenn Feunteun <[email protected]>

* Update pkg/api/admin/administration.go

Co-authored-by: Glenn Feunteun <[email protected]>

* Update rks-openapi.yaml

Co-authored-by: Glenn Feunteun <[email protected]>

Co-authored-by: Glenn Feunteun <[email protected]>
  • Loading branch information
celinenicolas22 and gfeun authored Jun 15, 2020
1 parent a14e088 commit 0fb1017
Show file tree
Hide file tree
Showing 6 changed files with 124 additions and 3 deletions.
27 changes: 27 additions & 0 deletions pkg/api/admin/administration.go
Original file line number Diff line number Diff line change
Expand Up @@ -667,3 +667,30 @@ func GetGroupConfig(w http.ResponseWriter, r *http.Request) {
}
logger.WithResponseStatus(customLogger, w).Info("get group config")
}

func RevokeNode(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
group := vars["groupname"]
nodeId := vars["nodeId"]

customlogger := logger.NewLoggerFromContext(r.Context()).WithFields(log.Fields{"groupname": group, "nodeId": nodeId})

vaultClient, rksErr := vault.NewVaultClientFromHTTPRequest(r)
if rksErr != nil {
rksErr.HandleErr(r.Context(), w)
return
}
if exists, rksErr := vaultClient.GroupExists(group); rksErr != nil {
rksErr.HandleErr(r.Context(), w)
return
} else if !exists {
(&model.RksError{WrappedError: nil, Message: "Group not found", Code: 404}).HandleErr(r.Context(), w)
return
}
if rksErr = vaultClient.RevokeNodeToken(group, nodeId); rksErr != nil {
rksErr.HandleErr(r.Context(), w)
return
}
w.WriteHeader(http.StatusNoContent)
customlogger.Info("revoke node")
}
6 changes: 6 additions & 0 deletions pkg/api/routers.go
Original file line number Diff line number Diff line change
Expand Up @@ -245,4 +245,10 @@ var routes = map[string]Route{"Index": {"GET", "/", false, Index}, "Login": {
false,
node.RegisterNode,
},
"RevokeNode": {
strings.ToUpper("Delete"),
"/rks/v1/group/{groupname:[a-zA-Z0-9\\-]{1,64}}/nodes/{nodeId}",
false,
admin.RevokeNode,
},
}
10 changes: 10 additions & 0 deletions pkg/vault/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,16 @@ func (v *Vault) CreateNodeTokenRole(group string, nodeID string) *model.RksError
return nil
}

func (v *Vault) RevokeNodeToken(group string, nodeID string) *model.RksError {
url := fmt.Sprintf("/auth/token/create/%s-%s", group, nodeID)

err := v.Sys().RevokePrefix(url)
if err != nil {
return RKSErrFromVaultErr(err, fmt.Sprintf("Couldn't Revoke Token for node %s in groupname %s unable to register node ", nodeID, group))
}
return nil
}

func (v *Vault) CreateNodeTokenFromRole(group string, nodeID string) (*vaultAPI.Secret, *model.RksError) {
url := fmt.Sprintf("/auth/token/create/%s-%s", group, nodeID)
auth, err := v.Logical().Write(url, map[string]interface{}{})
Expand Down
4 changes: 4 additions & 0 deletions pkg/vault/policy.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ path "sys/policies/*" {
capabilities = ["create","update","read","delete"]
}
path "sys/leases/revoke-prefix/auth/token/*" {
capabilities = ["sudo","create","update","read","delete"]
}
path "auth/token/lookup-self" {
capabilities = ["read"]
}
Expand Down
38 changes: 35 additions & 3 deletions rks-openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,29 @@ paths:
description: "Forbidden. Invalid X-Vault-Token"
'404':
description: Group not found
'/rks/v1/group/{groupname}/nodes/{nodeId}':
delete:
summary: Revoke a Node by revoking its token
description: |
revoke the **nodeToken** for a node part of group **groupname** with nodeId **X-LCDN-nodeId**,
**adminToken** is used as X-Vault-Token for authentication.
Note that this call will revoke the **nodeToken** but won't forbid the node to register again.
To forbid node registration there are two ways:
Make group manager callback url answer "40X" for this nodeId
Renew the group grouptoken and spread it to all nodes, except this one
tags:
- RKS Administration
operationId: revokeNode
parameters:
- $ref: '#/components/parameters/groupname'
- $ref: '#/components/parameters/nodeIdPath'
responses:
'204':
description: Node successfully deleted
'403':
description: "Forbidden. Invalid X-Vault-Token"
'404':
description: Group not found
'/rks/v1/group/{groupname}/secrets':
get:
summary: Get secrets associated with **groupname**
Expand Down Expand Up @@ -297,7 +320,7 @@ paths:
- RKS Node Setup
operationId: registerNode
parameters:
- $ref: '#/components/parameters/nodeId'
- $ref: '#/components/parameters/nodeIdHeader'
responses:
'201':
description: Node successfully registered
Expand Down Expand Up @@ -460,7 +483,17 @@ components:
schema:
type: string
example: "test.com"
nodeId:
nodeIdPath:
name: nodeId
in: path
required: true
description: |
**nodeID**
schema:
type: string
example: "8c03fb4a-007f-11ea-9383-0fd702e68c30"
pattern: "^[a-zA-Z0-9\\-]{1,64}$"
nodeIdHeader:
name: X-LCDN-nodeId
in: header
required: true
Expand Down Expand Up @@ -608,4 +641,3 @@ components:
+9xiOEcTNrlo9vuonkMoyiwDua6H90vv3sgBJ80WDTn6sW/SXRTwDbE8Dn9ODv65
adVJ9a+aAf+SYT8HpMNezvro
-----END PRIVATE KEY-----
42 changes: 42 additions & 0 deletions tests/test/test_rks_administration_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -435,3 +435,45 @@ def test_get_secrets_groups(self, admin_api, group_token, test_dot_com_secret):
with pytest.raises(ApiException) as excinfo:
group_names = admin_api.get_secret_groups("testnotexist.com")
assert excinfo.value.status == 404

def test_revoke_node(
self,
admin_api,
secret_api,
node_token,
associate_dot_com_group,
test_dot_com_secret,
):

secret_api.api_client.configuration.api_key["X-Vault-Token"] = node_token

secret = secret_api.get_secret("test.com")

assert secret.data != None, "revoke failed"
assert secret.data.certificate != None, "revoke failed"
assert secret.data.private_key != None, "revoke failed"
assert secret.data.meta != None, "revoke failed"

_, status, headers = admin_api.revoke_node_with_http_info("fakecdn1", "1")

assert status == 204, "revoke node does not return 204 as expected"

try:
secret = secret_api.get_secret("test.com")
except ApiException as e:
assert (
e.status == 403
), "getting secret with revoked nodeToken does not return 403 as expected"

# test revoke unknown nodeId
_, status, headers = admin_api.revoke_node_with_http_info("fakecdn1", "10")

assert status == 204, "revoke unknown nodeId does not return 204 as expected"

with pytest.raises(ApiException) as ex:
# test revoke unknown groupname nodeId
admin_api.revoke_node("unknowngroupname", "1")

assert (
ex.value.status == 404
), "revoke nodeId from unknown group does not return 404 as expected"

0 comments on commit 0fb1017

Please sign in to comment.