Basic implementation of client: render qa code and scan from mobile app
diff --git a/core/nebula/api/main.go b/core/nebula/api/main.go
index ed09135..c0c4817 100644
--- a/core/nebula/api/main.go
+++ b/core/nebula/api/main.go
@@ -1,8 +1,8 @@
package main
import (
- "context"
"embed"
+ "encoding/json"
"flag"
"fmt"
"html/template"
@@ -11,17 +11,17 @@
"github.com/gorilla/mux"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
- nebulav1 "github.com/giolekva/pcloud/core/nebula/controller/apis/nebula/v1"
clientset "github.com/giolekva/pcloud/core/nebula/controller/generated/clientset/versioned"
)
var port = flag.Int("port", 8080, "Port to listen on.")
var kubeConfig = flag.String("kubeconfig", "", "Path to a kubeconfig. Only required if out-of-cluster.")
var masterURL = flag.String("master", "", "The address of the Kubernetes API server. Overrides any value in kubeconfig. Only required if out-of-cluster.")
+var namespace = flag.String("namespace", "", "Namespace where Nebula CA and Node secrets are stored.")
+var caSecretName = flag.String("ca-secret-name", "", "Name of the Nebula CA secret storing certificate information.")
//go:embed templates/*
var tmpls embed.FS
@@ -38,99 +38,6 @@
return &Templates{index}, nil
}
-type nebulaCA struct {
- Name string
- Namespace string
- Nodes []nebulaNode
-}
-
-type nebulaNode struct {
- Name string
- Namespace string
- IP string
-}
-
-type Manager struct {
- kubeClient kubernetes.Interface
- nebulaClient clientset.Interface
-}
-
-func (m *Manager) ListAll() ([]*nebulaCA, error) {
- ret := make([]*nebulaCA, 0)
- cas, err := m.nebulaClient.LekvaV1().NebulaCAs("").List(context.TODO(), metav1.ListOptions{})
- if err != nil {
- return nil, err
- }
- for _, ca := range cas.Items {
- ret = append(ret, &nebulaCA{
- Name: ca.Name,
- Namespace: ca.Namespace,
- Nodes: make([]nebulaNode, 0),
- })
- }
- nodes, err := m.nebulaClient.LekvaV1().NebulaNodes("").List(context.TODO(), metav1.ListOptions{})
- if err != nil {
- return nil, err
- }
- for _, node := range nodes.Items {
- for _, ca := range ret {
- if ca.Name == node.Spec.CAName {
- ca.Nodes = append(ca.Nodes, nebulaNode{
- Name: node.Name,
- Namespace: node.Namespace,
- IP: node.Spec.IPCidr,
- })
- }
- }
- }
- return ret, nil
-}
-
-func (m *Manager) createNode(namespace, name, caNamespace, caName, ipCidr, pubKey string) (string, string, error) {
- node := &nebulav1.NebulaNode{
- ObjectMeta: metav1.ObjectMeta{
- Name: name,
- Namespace: namespace,
- },
- Spec: nebulav1.NebulaNodeSpec{
- CAName: caName,
- CANamespace: caNamespace,
- IPCidr: ipCidr,
- PubKey: pubKey,
- SecretName: fmt.Sprintf("%s-cert", name),
- },
- }
- node, err := m.nebulaClient.LekvaV1().NebulaNodes(namespace).Create(context.TODO(), node, metav1.CreateOptions{})
- if err != nil {
- return "", "", err
- }
- return node.Namespace, node.Name, nil
-}
-
-func (m *Manager) getNodeCertQR(namespace, name string) ([]byte, error) {
- node, err := m.nebulaClient.LekvaV1().NebulaNodes(namespace).Get(context.TODO(), name, metav1.GetOptions{})
- if err != nil {
- return nil, err
- }
- secret, err := m.kubeClient.CoreV1().Secrets(namespace).Get(context.TODO(), node.Spec.SecretName, metav1.GetOptions{})
- if err != nil {
- return nil, err
- }
- return secret.Data["host.png"], nil
-}
-
-func (m *Manager) getCACertQR(namespace, name string) ([]byte, error) {
- ca, err := m.nebulaClient.LekvaV1().NebulaCAs(namespace).Get(context.TODO(), name, metav1.GetOptions{})
- if err != nil {
- return nil, err
- }
- secret, err := m.kubeClient.CoreV1().Secrets(namespace).Get(context.TODO(), ca.Spec.SecretName, metav1.GetOptions{})
- if err != nil {
- return nil, err
- }
- return secret.Data["ca.png"], nil
-}
-
type Handler struct {
mgr Manager
tmpls *Templates
@@ -151,7 +58,7 @@
vars := mux.Vars(r)
namespace := vars["namespace"]
name := vars["name"]
- qr, err := h.mgr.getNodeCertQR(namespace, name)
+ qr, err := h.mgr.GetNodeCertQR(namespace, name)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
@@ -163,7 +70,7 @@
vars := mux.Vars(r)
namespace := vars["namespace"]
name := vars["name"]
- qr, err := h.mgr.getCACertQR(namespace, name)
+ qr, err := h.mgr.GetCACertQR(namespace, name)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
@@ -176,7 +83,7 @@
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
- _, _, err := h.mgr.createNode(
+ _, _, err := h.mgr.CreateNode(
r.FormValue("node-namespace"),
r.FormValue("node-name"),
r.FormValue("ca-namespace"),
@@ -191,6 +98,66 @@
http.Redirect(w, r, "/", http.StatusSeeOther)
}
+func (h *Handler) getNextIP(w http.ResponseWriter, r *http.Request) {
+ ip, err := h.mgr.getNextIP()
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+ fmt.Fprint(w, ip)
+}
+
+type signReq struct {
+ Message []byte `json:"message"`
+}
+
+type signResp struct {
+ Signature []byte `json:"signature"`
+}
+
+func (h *Handler) sign(w http.ResponseWriter, r *http.Request) {
+ var req signReq
+ if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ return
+ }
+ signature, err := h.mgr.Sign(req.Message)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+ w.Header().Set("Content-Type", "application/json")
+ resp := signResp{
+ signature,
+ }
+ if err := json.NewEncoder(w).Encode(resp); err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+}
+
+type verifyReq struct {
+ Message []byte `json:"message"`
+ Signature []byte `json:"signature"`
+}
+
+func (h *Handler) verify(w http.ResponseWriter, r *http.Request) {
+ var req verifyReq
+ if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ return
+ }
+ valid, err := h.mgr.VerifySignature(req.Message, req.Signature)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+ if !valid {
+ http.Error(w, "Signature could not be verified", http.StatusBadRequest)
+ return
+ }
+}
+
func main() {
flag.Parse()
cfg, err := clientcmd.BuildConfigFromFlags(*masterURL, *kubeConfig)
@@ -209,12 +176,17 @@
mgr := Manager{
kubeClient: kubeClient,
nebulaClient: nebulaClient,
+ namespace: *namespace,
+ caSecretName: *caSecretName,
}
handler := Handler{
mgr: mgr,
tmpls: t,
}
r := mux.NewRouter()
+ r.HandleFunc("/api/ip", handler.getNextIP)
+ r.HandleFunc("/api/sign", handler.sign)
+ r.HandleFunc("/api/verify", handler.verify)
r.HandleFunc("/node/{namespace:[a-zA-z0-9-]+}/{name:[a-zA-z0-9-]+}", handler.handleNode)
r.HandleFunc("/ca/{namespace:[a-zA-z0-9-]+}/{name:[a-zA-z0-9-]+}", handler.handleCA)
r.HandleFunc("/sign-node", handler.handleSignNode)