Skip to content

Commit

Permalink
wip: nkey model
Browse files Browse the repository at this point in the history
  • Loading branch information
katallaxie authored Apr 23, 2024
1 parent 50d0ee0 commit 42a551c
Show file tree
Hide file tree
Showing 13 changed files with 1,352 additions and 129 deletions.
163 changes: 153 additions & 10 deletions api/api.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,105 @@ paths:
schema:
$ref: "#/components/schemas/Version"

/keys:
get:
summary: List all NKeys
operationId: listKeys
tags:
- NKey
produces:
- "application/json"
parameters:
- $ref: "#/components/parameters/offsetParam"
- $ref: "#/components/parameters/limitParam"
security:
- bearerAuth: ["read:keys"]
responses:
"200":
description: Successfull response
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/PaginatedResult"
- type: object
properties:
results:
type: array
items:
$ref: "#/components/schemas/KeyPair"
post:
summary: Creates a new NKey
operationId: createKey
tags:
- NKey
produces:
- "application/json"
responses:
"201":
description: Created
content:
application/json:
schema:
$ref: "#/components/schemas/KeyPair"
links:
GetKeyById:
operationId: getKey
parameters:
keyId: "$response.body#/id"

/operators:
get:
summary: List all operators
operationId: listOperators
tags:
- Operator
produces:
- "application/json"
parameters:
- $ref: "#/components/parameters/offsetParam"
- $ref: "#/components/parameters/limitParam"
security:
- bearerAuth: ["read:operators"]
responses:
"200":
description: Successfull response
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/PaginatedResult"
- type: object
properties:
results:
type: array
items:
$ref: "#/components/schemas/Operator"
post:
summary: Creates a new operator
operationId: createOperator
tags:
- Operator
produces:
- "application/json"
requestBody:
content:
application/json:
schema:
$ref: "#/components/schemas/Operator"
responses:
"201":
description: Created
content:
application/json:
schema:
$ref: "#/components/schemas/Operator"
links:
GetOperatorById:
operationId: getOperator
parameters:
operatorId: "$response.body#/id"

/teams:
get:
summary: List all teams
Expand Down Expand Up @@ -476,6 +575,7 @@ paths:
application/json:
schema:
$ref: "#/components/schemas/System"

deleted:
summary: Deletes a system by ID
operationId: deleteSystem
Expand Down Expand Up @@ -568,6 +668,26 @@ components:
type: apiKey

schemas:
NKey:
description: |
An NKey is the private key of a NATS account.
type: string
format: base32

KeyPair:
descriptio: |
A KeyPair is a public/private key pair.
required:
- publicKey
type: object
properties:
publicKey:
type: string
format: base32
privateKey:
type: string
format: base32

PaginatedResult:
type: object
properties:
Expand Down Expand Up @@ -598,6 +718,8 @@ components:
description:
type: string
description: A description of the system.
operator:
$ref: "#/components/schemas/Operator"
cluster:
$ref: "#/components/schemas/Cluster"
createdAt:
Expand All @@ -616,7 +738,7 @@ components:
description: Creation date and time
example: "2021-01-30T08:30:00Z"

Team:
Operator:
type: object
required:
- name
Expand Down Expand Up @@ -647,7 +769,7 @@ components:
description: Creation date and time
example: "2021-01-30T08:30:00Z"

Cluster:
Team:
type: object
required:
- name
Expand All @@ -656,18 +778,39 @@ components:
type: string
format: uuid
readOnly: true
url:
name:
type: string
user:
description:
type: string
password:
contactEmail:
type: string
createdAt:
type: string
format: date-time
description: Creation date and time
example: "2021-01-30T08:30:00Z"
updatedAt:
type: string
operatorSignKey:
$ref: "#/components/schemas/OperatorSignKey"
format: date-time
description: Creation date and time
example: "2021-01-30T08:30:00Z"
deletedAt:
type: string
format: date-time
description: Creation date and time
example: "2021-01-30T08:30:00Z"

OperatorSignKey:
type: string
format: base64
Cluster:
type: object
required:
- name
properties:
id:
type: string
format: uuid
readOnly: true
url:
type: string

Account:
type: object
Expand Down
172 changes: 172 additions & 0 deletions cmd/examples/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
package main

import (
"fmt"
"log"

"github.com/nats-io/jwt"
"github.com/nats-io/nkeys"
)

func main() {
// op, err := nkeys.CreateOperator()
// if err != nil {
// log.Fatal(err)
// }
// seed, err := op.Seed()
// if err != nil {
// log.Fatal(err)
// }
// fmt.Println(string(seed))
// fmt.Println(op.PublicKey())

// op, err = nkeys.FromSeed(seed)
// if err != nil {
// log.Fatal(err)
// }
// seed, err = op.Seed()
// if err != nil {
// log.Fatal(err)
// }
// fmt.Println(string(seed))
// fmt.Println(op.PublicKey())

// // create an operator key pair (private key)
okp, err := nkeys.CreateOperator()
if err != nil {
log.Fatal(err)
}

fmt.Println(okp.PublicKey())

// extract the public key
opk, err := okp.PublicKey()
if err != nil {
log.Fatal(err)
}

// create an operator claim using the public key for the identifier
oc := jwt.NewOperatorClaims(opk)
oc.Name = "O"

// add an operator signing key to sign accounts
oskp, err := nkeys.CreateOperator()
if err != nil {
log.Fatal(err)
}

// get the public key for the signing key
ospk, err := oskp.PublicKey()
if err != nil {
log.Fatal(err)
}

// add the signing key to the operator - this makes any account
// issued by the signing key to be valid for the operator
oc.SigningKeys.Add(ospk)

fmt.Println(oc)

// self-sign the operator JWT - the operator trusts itself
// operatorJWT, err := oc.Encode(okp)
// if err != nil {
// log.Fatal(err)
// }
// fmt.Println(operatorJWT)

// create an account keypair
akp, err := nkeys.CreateAccount()
if err != nil {
log.Fatal(err)
}
// extract the public key for the account
apk, err := akp.PublicKey()
if err != nil {
log.Fatal(err)
}

// create the claim for the account using the public key of the account
ac := jwt.NewAccountClaims(apk)
ac.Name = "A"
// create a signing key that we can use for issuing users
askp, err := nkeys.CreateAccount()
if err != nil {
log.Fatal(err)
}

// extract the public key
aspk, err := askp.PublicKey()
if err != nil {
log.Fatal(err)
}

// add the signing key (public) to the account
ac.SigningKeys.Add(aspk)

fmt.Println(ac)

// now we could encode an issue the account using the operator
// key that we generated above, but this will illustrate that
// the account could be self-signed, and given to the operator
// who can then re-sign it
accountJWT, err := ac.Encode(akp)
if err != nil {
log.Fatal(err)
}

// the operator would decode the provided token, if the token
// is not self-signed or signed by an operator or tampered with
// the decoding would fail
ac, err = jwt.DecodeAccountClaims(accountJWT)
if err != nil {
log.Fatal(err)
}

// here the operator is going to use its private signing key to
// re-issue the account
accountJWT, err = ac.Encode(oskp)
if err != nil {
log.Fatal(err)
}

// // now back to the account, the account can issue users
// // need not be known to the operator - the users are trusted
// // because they will be signed by the account. The server will
// // look up the account get a list of keys the account has and
// // verify that the user was issued by one of those keys
// ukp, err := nkeys.CreateUser()
// if err != nil {
// log.Fatal(err)
// }
// fmt.Println(ukp)

// upk, err := ukp.PublicKey()
// if err != nil {
// log.Fatal(err)
// }
// fmt.Println(upk)

// uc := jwt.NewUserClaims(upk)
// // since the jwt will be issued by a signing key, the issuer account
// // must be set to the public ID of the account
// uc.IssuerAccount = apk
// userJwt, err := uc.Encode(askp)
// if err != nil {
// log.Fatal(err)
// }
// fmt.Println(userJwt)

// // the seed is a version of the keypair that is stored as text
// useed, err := ukp.Seed()
// if err != nil {
// log.Fatal(err)
// }
// fmt.Println(useed)

// // generate a creds formatted file that can be used by a NATS client
// creds, err := jwt.FormatUserConfig(userJwt, useed)
// if err != nil {
// log.Fatal(err)
// }
// fmt.Println(creds)
}
Loading

0 comments on commit 42a551c

Please sign in to comment.