Skip to content

Commit

Permalink
feat: add a sites and ca api
Browse files Browse the repository at this point in the history
* add feature flags for site, ca and device apis
* ca and site api documentation marks them experimental
* use spiffe style URIs in the certs
* add revision field to VPCs so they can be watched for changes.
* events API can now watch for VPC changes

Signed-off-by: Hiram Chirino <[email protected]>
  • Loading branch information
chirino committed Jan 10, 2024
1 parent fb18adc commit 632bcd6
Show file tree
Hide file tree
Showing 60 changed files with 5,656 additions and 149 deletions.
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -549,6 +549,7 @@ clear-db:
DROP TABLE IF EXISTS security_groups;\
DROP TABLE IF EXISTS device_metadata;\
DROP TABLE IF EXISTS devices;\
DROP TABLE IF EXISTS sites;\
DROP TABLE IF EXISTS user_organizations;\
DROP TABLE IF EXISTS vpcs;\
DROP TABLE IF EXISTS organizations;\
Expand Down
53 changes: 40 additions & 13 deletions cmd/apiserver/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"log"
"net"
"net/http"
"net/url"
"os"
"os/signal"
"sync"
Expand Down Expand Up @@ -54,23 +55,24 @@ func init() {
tracer = otel.Tracer("apiserver")
}

// @title Nexodus API
// @version 1.0
// @description This is the Nexodus API Server.
// @title Nexodus API
// @description This is the Nexodus API Server.
// @version 1.0
// @contact.name The Nexodus Authors
// @contact.url https://github.com/nexodus-io/nexodus/issues
// @license.name Apache 2.0
// @license.url http://www.apache.org/licenses/LICENSE-2.0.html
// @BasePath /

// @contact.name The Nexodus Authors
// @contact.url https://github.com/nexodus-io/nexodus/issues

// @license.name Apache 2.0
// @license.url http://www.apache.org/licenses/LICENSE-2.0.html
// @tag.name CA
// @tag.description X509 Certificate related APIs, these APIs are experimental and disabled by default. Use the feature flag apis to check if they are enabled on the server.
// @tag.name Sites
// @tag.description Skupper Site related APIs, these APIs are experimental and disabled by default. Use the feature flag apis to check if they are enabled on the server.

// @securitydefinitions.oauth2.implicit OAuth2Implicit
// @authorizationurl https://auth.try.nexodus.127.0.0.1.nip.io/
//
// @authorizationurl https://auth.try.nexodus.127.0.0.1.nip.io/
// @scope.admin Grants read and write access to administrative information
// @scope.user Grants read and write access to resources owned by this user

// @BasePath /
func main() {
// Override to capitalize "Show"
cli.HelpFlag.(*cli.BoolFlag).Usage = "Show help"
Expand Down Expand Up @@ -278,6 +280,18 @@ func main() {
Required: false,
Sources: cli.EnvVars("NEXAPI_SMTP_FROM"),
},
&cli.StringFlag{
Name: "ca-cert",
Usage: "Certificate authority cert",
Required: false,
Sources: cli.EnvVars("NEXAPI_CA_CERT"),
},
&cli.StringFlag{
Name: "ca-key",
Usage: "Certificate authority key",
Required: false,
Sources: cli.EnvVars("NEXAPI_CA_KEY"),
},
},

Action: func(ctx context.Context, command *cli.Command) error {
Expand Down Expand Up @@ -316,7 +330,16 @@ func main() {
session.SetStore(sessionStore),
)

api, err := handlers.NewAPI(ctx, logger.Sugar(), db, ipam, fflags, store, signalBus, redisClient, sessionManager)
caKeyPair := handlers.CertificateKeyPair{}
if command.String("ca-cert") != "" && command.String("ca-key") != "" {
var err error
caKeyPair, err = handlers.ParseCertificateKeyPair([]byte(command.String("ca-cert")), []byte(command.String("ca-key")))
if err != nil {
log.Fatal("invalid --ca-cert or --ca-key values:", err)
}
}

api, err := handlers.NewAPI(ctx, logger.Sugar(), db, ipam, fflags, store, signalBus, redisClient, sessionManager, caKeyPair)
if err != nil {
log.Fatal(err)
}
Expand Down Expand Up @@ -381,6 +404,10 @@ func main() {
log.Fatal(fmt.Errorf("invalid tls-key: %w", err))
}
api.URL = command.String("url")
api.URLParsed, err = url.Parse(api.URL)
if err != nil {
log.Fatal(fmt.Errorf("invalid url: %w", err))
}

router, err := routers.NewAPIRouter(ctx, routers.APIRouterOptions{
Logger: logger.Sugar(),
Expand Down
1 change: 1 addition & 0 deletions cmd/nexctl/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ func main() {
createDeviceCommand(),
createUserSubCommand(),
createSecurityGroupCommand(),
createSiteCommand(),
createInvitationCommand(),
},
}
Expand Down
128 changes: 128 additions & 0 deletions cmd/nexctl/site.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
package main

import (
"context"
"github.com/google/uuid"
"github.com/nexodus-io/nexodus/internal/api/public"
"github.com/urfave/cli/v3"
"log"
)

func createSiteCommand() *cli.Command {
return &cli.Command{
Name: "site",
Hidden: true,
Usage: "Commands relating to sites",
Commands: []*cli.Command{
{
Name: "list",
Usage: "List all sites",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "vpc-id",
Value: "",
Required: false,
},
},
Action: func(ctx context.Context, command *cli.Command) error {
orgID := command.String("vpc-id")
if orgID != "" {
id, err := uuid.Parse(orgID)
if err != nil {
log.Fatal(err)
}
return listVpcSites(ctx, command, id)
}
return listAllSites(ctx, command)
},
},
{
Name: "delete",
Usage: "Delete a site",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "site-id",
Required: true,
},
},
Action: func(ctx context.Context, command *cli.Command) error {
devID := command.String("site-id")
return deleteSite(ctx, command, devID)
},
},
{
Name: "update",
Usage: "Update a site",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "site-id",
Required: true,
},
&cli.StringFlag{
Name: "hostname",
Required: false,
},
},
Action: func(ctx context.Context, command *cli.Command) error {
devID := command.String("site-id")
update := public.ModelsUpdateSite{}
if command.IsSet("hostname") {
update.Hostname = command.String("hostname")
}
return updateSite(ctx, command, devID, update)
},
},
},
}
}
func siteTableFields(command *cli.Command) []TableField {
var fields []TableField
fields = append(fields, TableField{Header: "SITE ID", Field: "Id"})
fields = append(fields, TableField{Header: "HOSTNAME", Field: "Hostname"})
fields = append(fields, TableField{Header: "VPC ID", Field: "VpcId"})
fields = append(fields, TableField{Header: "PUBLIC KEY", Field: "PublicKey"})
fields = append(fields, TableField{Header: "OS", Field: "Os"})
return fields
}

func listAllSites(ctx context.Context, command *cli.Command) error {
c := createClient(ctx, command)
sites := apiResponse(c.SitesApi.ListSites(context.Background()).Execute())
show(command, siteTableFields(command), sites)
return nil
}

func listVpcSites(ctx context.Context, command *cli.Command, vpcId uuid.UUID) error {
c := createClient(ctx, command)
sites := apiResponse(c.VPCApi.ListSitesInVPC(context.Background(), vpcId.String()).Execute())
show(command, siteTableFields(command), sites)
return nil
}

func deleteSite(ctx context.Context, command *cli.Command, devID string) error {
devUUID, err := uuid.Parse(devID)
if err != nil {
log.Fatalf("failed to parse a valid UUID from %s %v", devUUID, err)
}
c := createClient(ctx, command)
res := apiResponse(c.SitesApi.DeleteSite(context.Background(), devUUID.String()).Execute())
show(command, orgTableFields(), res)
showSuccessfully(command, "deleted")
return nil
}

func updateSite(ctx context.Context, command *cli.Command, devID string, update public.ModelsUpdateSite) error {
devUUID, err := uuid.Parse(devID)
if err != nil {
log.Fatalf("failed to parse a valid UUID from %s %v", devUUID, err)
}

c := createClient(ctx, command)
res := apiResponse(c.SitesApi.
UpdateSite(context.Background(), devUUID.String()).
Update(update).
Execute())
show(command, orgTableFields(), res)
showSuccessfully(command, "updated")
return nil
}
22 changes: 22 additions & 0 deletions deploy/nexodus/base/apiserver/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,28 @@ spec:
name: smtp-server
key: NEXAPI_SMTP_USER
optional: true
- name: NEXAPI_CA_CERT
valueFrom:
secretKeyRef:
name: nexodus-ca-key-pair
key: ca.crt
optional: true
- name: NEXAPI_CA_KEY
valueFrom:
secretKeyRef:
name: nexodus-ca-key-pair
key: tls.key
optional: true
- name: NEXAPI_FFLAG_DEVICES
valueFrom:
configMapKeyRef:
name: apiserver
key: NEXAPI_FFLAG_DEVICES
- name: NEXAPI_FFLAG_SITES
valueFrom:
configMapKeyRef:
name: apiserver
key: NEXAPI_FFLAG_SITES

# CI deployment seems to fail when this is enabled
# readinessProbe:
Expand Down
2 changes: 2 additions & 0 deletions deploy/nexodus/base/apiserver/kustomization.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ configMapGenerator:
- NEXAPI_FETCH_MGR=redis
- NEXAPI_FETCH_MGR_TIMEOUT=2s
- NEXAPI_DEVICE_CACHE_SIZE=500
- NEXAPI_FFLAG_DEVICES=true
- NEXAPI_FFLAG_SITES=true
resources:
- service.yaml
- deployment.yaml
Expand Down
12 changes: 10 additions & 2 deletions deploy/nexodus/overlays/dev/issuer.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,16 @@ spec:
commonName: nexodus-selfsigned-ca
secretName: nexodus-ca-key-pair
privateKey:
algorithm: ECDSA
size: 256
algorithm: RSA
size: 2048
encoding: PKCS1
uris:
- https://try.nexodus.127.0.0.1.nip.io
usages:
- digital signature
- key encipherment
- crl sign
- cert sign
issuerRef:
name: selfsigned-issuer
kind: Issuer
Expand Down
39 changes: 39 additions & 0 deletions deploy/nexodus/overlays/openshift/issuer.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,42 @@ spec:
- http01:
ingress:
serviceType: ClusterIP
---
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: selfsigned-issuer
spec:
selfSigned: {}
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: nexodus-selfsigned-ca
spec:
isCA: true
commonName: nexodus-selfsigned-ca
secretName: nexodus-ca-key-pair
privateKey:
algorithm: RSA
size: 2048
encoding: PKCS1
uris:
- https://try.nexodus.127.0.0.1.nip.io
usages:
- digital signature
- key encipherment
- crl sign
- cert sign
issuerRef:
name: selfsigned-issuer
kind: Issuer
group: cert-manager.io
---
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: nexodus-issuer
spec:
ca:
secretName: nexodus-ca-key-pair
3 changes: 3 additions & 0 deletions deploy/nexodus/overlays/playground/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
apiserver-ca.yaml
secret.yaml
secret-smtp.yaml
11 changes: 6 additions & 5 deletions deploy/nexodus/overlays/playground/kustomization.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,34 +6,35 @@ resources:
namespace: nexodus-playground
configMapGenerator:
- behavior: replace
name: auth-config
literals:
- hostname=auth.playground.nexodus.io
- frontend-url=https://playground.nexodus.io
name: auth-config
- behavior: replace
name: realm
files:
- files/nexodus.json
name: realm
- behavior: merge
name: apiproxy
literals:
- APIPROXY_API_URL=https://api.playground.nexodus.io
- APIPROXY_OIDC_URL=https://auth.playground.nexodus.io/realms/nexodus
- APIPROXY_API_DOMAIN=api.playground.nexodus.io
- APIPROXY_WEB_DOMAIN=playground.nexodus.io
- APIPROXY_WEB_ORIGINS=https://playground.nexodus.io
- ENVOY_COMP_LOG_LEVEL=upstream:info,http:info,router:info,jwt:info
name: apiproxy
- behavior: merge
name: apiserver
literals:
- NEXAPI_URL=https://api.playground.nexodus.io
- NEXAPI_OIDC_URL=https://auth.playground.nexodus.io/realms/nexodus
- NEXAPI_DOMAIN=api.playground.nexodus.io
- NEXAPI_REDIRECT_URL=https://playground.nexodus.io/#/login
- NEXAPI_ORIGINS=https://playground.nexodus.io
- NEXAPI_ENVIRONMENT=qa
- NEXAPI_FFLAG_SECURITY_GROUPS=true
- NEXAPI_FFLAG_DEVICES=false
- NEXAPI_FFLAG_SITES=true
- NEXAPI_DEBUG=0
name: apiserver
patches:

# Update the dns names for the certificates
Expand Down
3 changes: 3 additions & 0 deletions deploy/nexodus/overlays/prod/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
apiserver-ca.yaml
secret.yaml
secret-smtp.yaml
3 changes: 3 additions & 0 deletions deploy/nexodus/overlays/qa/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
apiserver-ca.yaml
secret.yaml
secret-smtp.yaml
Loading

0 comments on commit 632bcd6

Please sign in to comment.