Skip to content

Commit

Permalink
feat(license): implement license validation
Browse files Browse the repository at this point in the history
Signed-off-by: sahil <sahilraja242@gmail.com>
  • Loading branch information
rajaSahil committed Apr 9, 2023
1 parent 46f29f4 commit 24529c5
Show file tree
Hide file tree
Showing 8 changed files with 230 additions and 49 deletions.
76 changes: 53 additions & 23 deletions src/cluster/k8sClientHandler.go
Original file line number Diff line number Diff line change
Expand Up @@ -503,13 +503,13 @@ func GetKubearmorRelayURL() string {
return url
}

func GetSecrets(k8sClient *kubernetes.Clientset) (*v1.Secret, error) {
func GetSecrets(k8sClient *kubernetes.Clientset, label string) (*v1.Secret, error) {
if k8sClient == nil {
return nil, errors.New("k8s client not created")
}

secrets, err := k8sClient.CoreV1().Secrets("").List(context.Background(), metav1.ListOptions{
LabelSelector: "license=discovery-engine",
LabelSelector: label,
})

if err != nil {
Expand All @@ -520,53 +520,83 @@ func GetSecrets(k8sClient *kubernetes.Clientset) (*v1.Secret, error) {
return nil, nil
}

if len(secrets.Items) > 1 {
return nil, errors.New("error while getting secrets, error: more than 1 secrets exists for license")
}

return &secrets.Items[0], nil

}

func CreateSecret(k8sClient *kubernetes.Clientset) (*v1.Secret, error) {
func CreateLicenseSecret(k8sClient *kubernetes.Clientset, key string, userId string) (*v1.Secret, error) {
if k8sClient == nil {
return nil, errors.New("k8s client not created")
}

secret, err := GetSecrets(k8sClient)
secret, err := GetSecrets(k8sClient, "app:discovery-engine")

if err != nil {
log.Error().Msgf(err.Error())
log.Error().Msgf("error while fetching secrets, error: %s", err.Error())
return nil, err
}

if secret != nil {
return secret, nil
}
t := true

scrt := v1.Secret{
TypeMeta: metav1.TypeMeta{},
ObjectMeta: metav1.ObjectMeta{},
Immutable: nil,
Data: nil,
StringData: nil,
Type: "",
secretSpec := v1.Secret{
ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{
"app": "discovery-engine",
},
},
Immutable: &t,
Data: nil,
StringData: map[string]string{
"key": key,
"user-id": userId,
},
Type: v1.SecretTypeOpaque,
}

secret, err := k8sClient.CoreV1().Secrets("").Create(context.Background(), &scrt, metav1.CreateOptions{})
secret, err = k8sClient.CoreV1().Secrets("").Create(context.Background(), &secretSpec, metav1.CreateOptions{})
if err != nil {
log.Error().Msgf("error while creating secret for license key, error: %s", err.Error())
return nil, err
}
return secret, nil
}

func DeleteSecret(k8sClient *kubernetes.Clientset, secretName string) error {
func DeleteSecrets(k8sClient *kubernetes.Clientset, label string) error {
if k8sClient == nil {
return errors.New("k8s client not created")
}

_, err := k8sClient.CoreV1().Secrets("").Delete(context.Background(), secretName, metav1.DeleteOptions{
TypeMeta: metav1.TypeMeta{},
GracePeriodSeconds: nil,
Preconditions: nil,
OrphanDependents: nil,
PropagationPolicy: nil,
DryRun: nil,
})

err := k8sClient.CoreV1().Secrets("").DeleteCollection(context.Background(), metav1.DeleteOptions{},
metav1.ListOptions{
LabelSelector: label,
})
if err != nil {
log.Error().Msgf("error while deleting secrets for discovery-engine, error: %s", err.Error())
return err
}

return nil
}

func GetKubeSystemUUID(k8sClient *kubernetes.Clientset) (string, error) {
if k8sClient == nil {
return "", errors.New("k8s client not created")
}

kubeSystem, err := k8sClient.CoreV1().Namespaces().Get(context.Background(), "kube-system", metav1.GetOptions{})
if err != nil {
return "", err
}

uuid := string(kubeSystem.GetUID())

return uuid, nil

}
1 change: 1 addition & 0 deletions src/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ require (
github.com/magiconair/properties v1.8.5 // indirect
github.com/mailru/easyjson v0.7.6 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
github.com/mervick/aes-everywhere/go/aes256 v0.0.0-20220903070135-f13ed3789ae1 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/mapstructure v1.4.3 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
Expand Down
2 changes: 2 additions & 0 deletions src/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -687,6 +687,8 @@ github.com/mdlayher/netlink v1.3.0/go.mod h1:xK/BssKuwcRXHrtN04UBkwQ6dY9VviGGuri
github.com/mdlayher/netlink v1.4.0/go.mod h1:dRJi5IABcZpBD2A3D0Mv/AiX8I9uDEu5oGkAVrekmf8=
github.com/mdlayher/raw v0.0.0-20190313224157-43dbcdd7739d/go.mod h1:r1fbeITl2xL/zLbVnNHFyOzQJTgr/3fpf1lJX/cjzR8=
github.com/mdlayher/raw v0.0.0-20190606142536-fef19f00fc18/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg=
github.com/mervick/aes-everywhere/go/aes256 v0.0.0-20220903070135-f13ed3789ae1 h1:RLYNaO6dcj6hms2FSzwsXlZsyjxQBJi8qO/8Vkilhz0=
github.com/mervick/aes-everywhere/go/aes256 v0.0.0-20220903070135-f13ed3789ae1/go.mod h1:Eb5RMoo9kOQra/2uRiUTGP+LfNuM13Vqm7y7P34+KKo=
github.com/mikioh/ipaddr v0.0.0-20190404000644-d465c8ab6721/go.mod h1:Ickgr2WtCLZ2MDGd4Gr0geeCH5HybhRJbonOgQpvSxc=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
Expand Down
130 changes: 122 additions & 8 deletions src/license/license.go
Original file line number Diff line number Diff line change
@@ -1,28 +1,142 @@
package license

import "github.com/golang-jwt/jwt"
import (
"errors"
"github.com/accuknox/auto-policy-discovery/src/cluster"
"github.com/golang-jwt/jwt"
"github.com/mervick/aes-everywhere/go/aes256"
"github.com/rs/zerolog/log"
"k8s.io/client-go/kubernetes"
"strings"
)

var privateKey = []byte("-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDZRSpD6aSjfkeH\nUQv5gPzMw3jPf7izocKLsK9EDQrFFUlsosDMwklGHb9sRXR+sR0mLuzbV4r3KWCZ\ncdI57FiFL3N+7MLHCEKW0BmlddAItqgVqvD9hd6r7pZonC0Jlmw2fSPlSLdNuKov\nZf1wX3NK4dqDZ0o7X4rQvJ/15mL/q6f4BvIQ2ay4LtXl72V+xGl5HNb/aAIjMnkt\nTKSF5Bhmfwh/G1O6Qtm1R/dT/WpAqfwWQlXRoUCOzsSAsQDaQ5OQOkRAWGH9CXVg\n645PHfYssAMGpEGS/GcI6kDaZXJ5nO9mVAFkmmi1cGZ/Y+CVYj5n8bBAiXoOpfnb\nrdgSPqllAgMBAAECggEAHEIYZ+pOsTv2miUioVITLx+aSiSStXxLtQbnGLr4hF8L\nJG+7kzYOuSmb0L1s1CB9ic6PHE0TxCczyulIniN89N+RzjeFcsUCgiJxP3ml88gr\n7tuDifm8FxEKK3NqkSVpECIxBbxyKM/khJMnhhLICDx9Qttvhm7b+1+ZD26mQBnK\nJCCXCc0LocXL1shfy9ot4rKjF+lbkd2zC6NorQDfCl4eMaWZZuNjNdeaRSzsWn+u\nJVA3HjAdUTzvZBPHCFTvqbwWJ1/IGEc2FiQhrIHLy2ZJ+HjcQh3/HkDfS8PHQ6WZ\nU3GA51Ulu380DW0ZSeoQn+IlLkJ3RIaDXph4BF6V0QKBgQD6DlmEMpT8rsnDljH1\noly5Sy45T7RxG4EYsD2q3/kyEaJSJkyz5/bc0OCiD3m2+ub2G8561hu2opKLkFgf\nk60q82EDS7nupmMUbuioAT2Z/107fs+uGGb8GRkqLSBCdHlqDXyJqw/H530J082B\nuZokmd0/FCiOnvzy8XcU3wNF8QKBgQDeb047d6fS0E9zju6beHvJ5FlJelFk8ubF\no7StRmTV2c8oYIRZc+wSesP/r4ipmLLtrmV0z4e+/y+7ZcJNdiHB/tVtgwLDnekn\nvjgYTHc5twhzKHLFlz5CoatVrvjyMqiy4mil1scfIxVKhqgIC66tE7KLk2t/jDqa\niPCEiiOWtQKBgQDxOxawqfuBKT4MKcFYrqG1QAn/0BzLYTVRk/Rp/FhzLP/jMH+e\nr5E/xWJv9W3+UF6v3nN7nUJvFrc5XK8nB1hvrwtQGqXszSeYdsaMDWZYQjq3Qscn\ntPLlEXFtdstAUQ0weoJCbXxz5aaC7Im9NEi4NpdyWwglTsvHs5qlz99ggQKBgD7V\ncGMKFQVPRPJe0PZoHYfVkodYH0AGAbyY1wQPm5JxWbyNLzXZsjkyJsXGfzNxaDIO\nDqjlqvIAQiqMv0uEcFrNstqhpJk/tUo9yLjMeO17z85AAdPhOnw2ESE+MSKxvsfx\nfyBBwLQCBBSuXy8OpcRMiSY2eappIXDf+BlosE71AoGBAIT3eGRR61+oRMIceYih\nL/TAMwmS4ZVNANrMhMw6U7Qy6myfnyUacXeY2GGJhWseYS6LhEI5kjYD+W1v7hK1\nbN0VkBMLpc3Y5w/FMpfUvE9X1lWzHZucVWw7LHWVnjgPdWlf23m11NujrPPab+9N\ndTLggo4D7JL2dfoXhr3U9O/A\n-----END PRIVATE KEY-----\n")

type ConfigLicense struct {
k8sClient *kubernetes.Clientset
}

type License struct {
UserId string
Key string
UserId string
Key string
PlatformUUID string
}

var cfg *ConfigLicense
var Tkn *Token

func InitializeConfig(k8sClient *kubernetes.Clientset) {
cfg = &ConfigLicense{k8sClient: k8sClient}
}

func CheckLicenseSecret() error {
log.Info().Msgf("fetching license secrets to validate discovery-engine licensing")
secret, err := cluster.GetSecrets(cfg.k8sClient, "app:discovery-engine")
if err != nil {
log.Error().Msgf("error while fetching secrets for discovery engine licensing, error: %s", err.Error())
return err
}
if secret == nil {
return nil
}

l := &License{
UserId: secret.StringData["user-id"],
Key: secret.StringData["key"],
}
err = l.ValidateLicense()

if err != nil {
log.Error().Msgf("error while validating license retrieved through secrets, error: %s", err.Error())
return err
}
log.Info().Msgf("license validation successfully for user-id: %s with key: %s", l.UserId, l.Key)
return nil
}

func (l *License) ValidateLicense() error {
var err error

l.PlatformUUID, err = cfg.getKubeSystemUUID()
if err != nil {
log.Error().Msgf("error while fetching uuid of kube-system namespace, error: %s", err.Error())
return err
}

decryptedKey, err := decryptKey(l.Key, l.PlatformUUID)
if err != nil {
log.Error().Msgf("error while decrypting license key, error: %s", err.Error())
return err
}

Tkn, err = validateToken(decryptedKey)
if err != nil {
log.Error().Msgf("error while validating jwt token")
return err
}

log.Info().Msgf("license validation successfully for user: %s with license key: %s", l.UserId, l.Key)

secret, err := cluster.CreateLicenseSecret(cfg.k8sClient, l.Key, l.UserId)
if err != nil {
log.Error().Msgf("error while creating secret for discovery engine license, error: %s", err.Error())
return err
}

log.Info().Msgf("secret created for discovery engine license with name: %s and uuid: %d", secret.GetName(), secret.GetUID())
return nil
}

func (cfg *ConfigLicense) getKubeSystemUUID() (string, error) {
uuid, err := cluster.GetKubeSystemUUID(cfg.k8sClient)
if err != nil {
log.Error().Msgf("error while fetching uuid of kube-system namespace, error: %s", err.Error())
return "", err
}
return uuid, nil
}

func decryptKey(key string, platformUUID string) (string, error) {
decryptedKey := aes256.Decrypt(key, platformUUID)
tokenSplit := strings.Split(decryptedKey, ".")
if len(tokenSplit) != 3 {
log.Error().Msgf("invalid licence key")
return "", errors.New("invalid license key")
}
return decryptedKey, nil
}

type Token struct {
jwt.Claims
jwt *jwt.Token
claims *jwt.MapClaims
}

func (t *Token) ValidateToken() error {
return nil
func validateToken(decryptedKey string) (*Token, error) {

claims := jwt.MapClaims{}

jwtToken, err := jwt.ParseWithClaims(decryptedKey, claims, func(token *jwt.Token) (interface{}, error) {
log.Info().Msgf("Signature: %v", token.Header)
return privateKey, nil
})
if err != nil {
log.Error().Msgf("error while parsing jwt token, error: %s", err.Error())
return nil, err
}
return &Token{
jwt: jwtToken,
claims: &claims,
}, nil
}

func checkUserID(c *jwt.Claims) bool {
func (t *Token) checkUserID() bool {
return false
}

func getFeatures(c *jwt.Claims) []string {
func (t *Token) getFeatures() []string {
return nil
}

func WatchFeatures(features []string, expTime string) error {
return nil
}
9 changes: 0 additions & 9 deletions src/license/secrets.go

This file was deleted.

19 changes: 16 additions & 3 deletions src/license/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,28 @@ package license
import (
"context"
ipb "github.com/accuknox/auto-policy-discovery/src/protobuf/v1/license"
"github.com/rs/zerolog/log"
)

type Server struct {
ipb.LicenseServer
ipb.UnimplementedLicenseServer
}

func (s *Server) InstallLicense(ctx context.Context, l *ipb.LicenseRequest) (*ipb.LicenseResponse, error) {
func (ls *Server) InstallLicense(ctx context.Context, lr *ipb.LicenseRequest) (*ipb.LicenseResponse, error) {
log.Info().Msgf("request received to install license for user-id: %s", lr.UserId)
l := License{
UserId: lr.UserId,
Key: lr.Key,
}
err := l.ValidateLicense()
if err != nil {
return &ipb.LicenseResponse{
Res: -1,
Message: "error while validating license",
}, err
}
return &ipb.LicenseResponse{
Res: 0,
Message: "",
Message: "license installed successfully",
}, nil
}
19 changes: 18 additions & 1 deletion src/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package main
import (
"github.com/accuknox/auto-policy-discovery/src/cluster"
"github.com/accuknox/auto-policy-discovery/src/config"
"github.com/accuknox/auto-policy-discovery/src/license"
"math/rand"
"net"
"os"
Expand Down Expand Up @@ -52,17 +53,33 @@ func init() {
// ========== //

func main() {

// check for license secret, if exist then validate
err := license.CheckLicenseSecret()
if err != nil {
log.Error().Msgf("error while validating license, error: %s", err.Error())
}

license.InitializeConfig(cfg.K8sClient)

// create server
lis, err := net.Listen("tcp", ":"+grpcserver.PortNumber)
if err != nil {
log.Error().Msgf("gRPC server failed to listen: %v", err)
os.Exit(1)
}
server := grpcserver.GetNewServer()

// starts grpc server
server := grpcserver.StartGrpcServer()
// add license server
server = grpcserver.AddLicenseServer(server)

server = grpcserver.AddServers(server)

// start autopolicy service
log.Info().Msgf("gRPC server on %s port started", grpcserver.PortNumber)
if err := server.Serve(lis); err != nil {
log.Error().Msgf("Failed to serve: %v", err)
}

}

0 comments on commit 24529c5

Please sign in to comment.