Skip to content

Commit

Permalink
Merge pull request #15 from aau-network-security/develop
Browse files Browse the repository at this point in the history
Release v1.0.0
  • Loading branch information
Mikkelhost authored Feb 13, 2024
2 parents 10c3a72 + 3863d47 commit ef4ceab
Show file tree
Hide file tree
Showing 22 changed files with 1,372 additions and 832 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,6 @@ logs
casbin.md
data
vms
.VSCodeCounter
.VSCodeCounter
log.log
pid
6 changes: 0 additions & 6 deletions config/config.example.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,6 @@ file-transfer-root: /path/to/desired/filetransfer/root
ova-dir: /path/to/desired/ova/directory
state-path: /path/to/desired/state/directory

exercise-service:
grpc: "localhost:port"
auth-key: dev-auth-key
sign-key: dev-sign-key
tls-enabled: false

vpn-service:
endpoint: vpn.localhost
port: 5353
Expand Down
2 changes: 0 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ go 1.18

require (
github.com/aau-network-security/gwireguard v1.0.5-0.20230311152758-128bc2b44342
github.com/aau-network-security/haaukins-exercises v1.2.2
github.com/dgrijalva/jwt-go v3.2.0+incompatible
github.com/fsouza/go-dockerclient v1.8.3
github.com/gin-contrib/cors v1.4.0
github.com/gin-gonic/gin v1.8.1
Expand Down
64 changes: 0 additions & 64 deletions go.sum

Large diffs are not rendered by default.

103 changes: 19 additions & 84 deletions internal/agent/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package agent
import (
"context"
"errors"
"fmt"
"io/ioutil"
"os"
"path/filepath"
Expand All @@ -15,25 +14,21 @@ import (
env "github.com/aau-network-security/haaukins-agent/internal/environment"
"github.com/aau-network-security/haaukins-agent/internal/environment/lab/virtual"
"github.com/aau-network-security/haaukins-agent/internal/worker"
"github.com/aau-network-security/haaukins-agent/pkg/proto"
pb "github.com/aau-network-security/haaukins-agent/pkg/proto"
eproto "github.com/aau-network-security/haaukins-exercises/proto"
"github.com/rs/zerolog/log"
"gopkg.in/yaml.v2"
)

var configPath string

type Agent struct {
initialized bool
config *Config
State *state.State
auth Authenticator
vlib *virtual.VboxLibrary
config *Config
State *state.State
auth Authenticator
vlib *virtual.VboxLibrary
pb.UnimplementedAgentServer
workerPool worker.WorkerPool
newLabs chan pb.Lab
ExClient eproto.ExerciseStoreClient
EnvPool *env.EnvPool `json:"envpool,omitempty"`
}

Expand Down Expand Up @@ -119,20 +114,6 @@ func New(conf *Config) (*Agent, error) {
}
}

var initialized = true
var exClient eproto.ExerciseStoreClient
// Check if exercise service has been configured by daemon
if conf.ExerciseService.Grpc == "" {
log.Debug().Msg("exercise service not yet configured, waiting for daemon to initiliaze...")
initialized = false
exClient = nil
} else {
exClient, err = NewExerciseClientConn(conf.ExerciseService)
if err != nil {
return nil, fmt.Errorf("error connecting to exercise service: %s", err)
}
}

// Creating and starting a workerPool for lab creation
// This is to ensure that resources are not spent without having them
// Workeramount can be configured from the config
Expand All @@ -145,27 +126,29 @@ func New(conf *Config) (*Agent, error) {
if err != nil {
log.Error().Err(err).Msg("error resuming state")
envPool = &env.EnvPool{
M: &sync.RWMutex{},
Envs: make(map[string]*env.Environment),
M: &sync.RWMutex{},
Envs: make(map[string]*env.Environment),
StartingEnvs: make(map[string]bool),
ClosingEnvs: make(map[string]bool),
}
}
if envPool == nil {
envPool = &env.EnvPool{
M: &sync.RWMutex{},
Envs: make(map[string]*env.Environment),
M: &sync.RWMutex{},
Envs: make(map[string]*env.Environment),
StartingEnvs: make(map[string]bool),
ClosingEnvs: make(map[string]bool),
}
}
// Creating agent struct
a := &Agent{
initialized: initialized,
config: conf,
workerPool: workerPool,
vlib: vlib,
auth: NewAuthenticator(conf.SignKey, conf.AuthKey),
newLabs: make(chan pb.Lab, 1000),
ExClient: exClient,
EnvPool: envPool,
State: &state.State{},
config: conf,
workerPool: workerPool,
vlib: vlib,
auth: NewAuthenticator(conf.SignKey, conf.AuthKey),
newLabs: make(chan pb.Lab, 1000),
EnvPool: envPool,
State: &state.State{},
}
return a, nil
}
Expand All @@ -192,51 +175,3 @@ func (d *Agent) NewGRPCServer(opts ...grpc.ServerOption) *grpc.Server {
}, opts...)
return grpc.NewServer(opts...)
}

// Connect to exdb based on what creds sent by daemon, and write to config
func (a *Agent) Init(ctx context.Context, req *proto.InitRequest) (*proto.StatusResponse, error) {
// Creating service config based on request from daemon
var exConf = ServiceConfig{
Grpc: req.Url,
AuthKey: req.AuthKey,
SignKey: req.SignKey,
TLSEnabled: req.TlsEnabled,
}
// Creating new exercise service connection from config
log.Debug().Msgf("request: %v", req)
exClient, err := NewExerciseClientConn(exConf)
if err != nil {
log.Error().Err(err).Msg("error connecting to exercise service")
return nil, fmt.Errorf("error connecting to exercise service: %s", err)
}

// Saving the config in the agent config
a.config.ExerciseService = exConf

// Updating the config
data, err := yaml.Marshal(a.config)
if err != nil {
log.Error().Err(err).Msg("error marshalling yaml")
return nil, fmt.Errorf("error marshalling yaml: %s", err)
}

// Truncates existing file to overwrite with new data
f, err := os.Create(configPath)
if err != nil {
log.Error().Err(err).Msg("error creating or truncating config file")
return nil, fmt.Errorf("error creating or truncating config file: %s", err)
}

if err := f.Chmod(0600); err != nil {
log.Error().Err(err).Msg("error changing file perms")
return nil, fmt.Errorf("error changing file perms: %s", err)
}

if _, err := f.Write(data); err != nil {
log.Error().Err(err).Msg("error writing config to file")
return nil, fmt.Errorf("error writing config to file: %s", err)
}
a.initialized = true
a.ExClient = exClient
return &proto.StatusResponse{Message: "OK"}, nil
}
1 change: 0 additions & 1 deletion internal/agent/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ type Config struct {
FileTransferRoot string `yaml:"file-transfer-root"`
OvaDir string `yaml:"ova-dir"`
StatePath string `yaml:"state-path"`
ExerciseService ServiceConfig `yaml:"exercise-service"`
VPNService VPNconf `yaml:"vpn-service"`
DockerRepositories []dockerclient.AuthConfiguration `yaml:"docker-repositories"`
GuacSSL bool `yaml:"guac-ssl"`
Expand Down
65 changes: 37 additions & 28 deletions internal/agent/environment.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import (
"github.com/aau-network-security/haaukins-agent/internal/environment/lab/virtual"
"github.com/aau-network-security/haaukins-agent/internal/state"
"github.com/aau-network-security/haaukins-agent/pkg/proto"
eproto "github.com/aau-network-security/haaukins-exercises/proto"
"github.com/rs/zerolog/log"
)

Expand All @@ -30,9 +29,13 @@ var (
// beginner events where the user would just need to press the connect button and a lab would be ready with all challenges running.
func (a *Agent) CreateEnvironment(ctx context.Context, req *proto.CreatEnvRequest) (*proto.StatusResponse, error) {
// Env for event already exists, Do not start a new guac container
if !a.initialized {
return nil, errors.New("agent not yet initialized")
}
a.EnvPool.AddStartingEnv(req.EventTag)
defer func() {
a.EnvPool.RemoveStartingEnv(req.EventTag)
if err := state.SaveState(a.EnvPool, a.config.StatePath); err != nil {
log.Error().Err(err).Msg("error saving state")
}
}()
log.Debug().Msgf("got createEnv request: %v", req)

if a.EnvPool.DoesEnvExist(req.EventTag) {
Expand All @@ -47,15 +50,10 @@ func (a *Agent) CreateEnvironment(ctx context.Context, req *proto.CreatEnvReques
envConf.WorkerPool = a.workerPool
envConf.TeamSize = int(req.TeamSize)
log.Debug().Str("envtype", envConf.Type.String()).Msg("making environment with type")
// Get exercise info from exercise db

exerDbConfs, err := a.ExClient.GetExerciseByTags(ctx, &eproto.GetExerciseByTagsRequest{Tag: req.Exercises})
if err != nil {
return nil, fmt.Errorf("error getting exercises: %s", err)
}
// Unpack into exercise slice
var exerConfs []exercise.ExerciseConfig
for _, e := range exerDbConfs.Exercises {
for _, e := range req.ExerciseConfigs {
ex, err := protobufToJson(e)
if err != nil {
return nil, err
Expand Down Expand Up @@ -165,7 +163,7 @@ func (a *Agent) CreateEnvironment(ctx context.Context, req *proto.CreatEnvReques
m.Lock()
env.Labs[lab.Tag] = &lab
m.Unlock()

// Should not be removed as it runs in a worker
if err := state.SaveState(a.EnvPool, a.config.StatePath); err != nil {
log.Error().Err(err).Msg("error saving state")
}
Expand All @@ -174,17 +172,25 @@ func (a *Agent) CreateEnvironment(ctx context.Context, req *proto.CreatEnvReques
}

// Start the environment
go env.Start(context.TODO())
if err := env.Start(context.TODO()); err != nil {
log.Error().Err(err).Msg("error creating environment")
return &proto.StatusResponse{Message: "Error creating environment"}, err
}

a.EnvPool.AddEnv(env)
if err := state.SaveState(a.EnvPool, a.config.StatePath); err != nil {
log.Error().Err(err).Msg("error saving state")
}
return &proto.StatusResponse{Message: "recieved createLabs request... starting labs"}, nil
}

// Closes environment and attached containers/vms, and removes the environment from the event pool
func (a *Agent) CloseEnvironment(ctx context.Context, req *proto.CloseEnvRequest) (*proto.StatusResponse, error) {
a.EnvPool.AddClosingEnv(req.EventTag)
defer func() {
a.EnvPool.RemoveClosingEnv(req.EventTag)
if err := state.SaveState(a.EnvPool, a.config.StatePath); err != nil {
log.Error().Err(err).Msg("error saving state")
}
}()

env, err := a.EnvPool.GetEnv(req.EventTag)
if err != nil {
log.Error().Str("envTag", req.EventTag).Msg("error finding finding environment with tag")
Expand All @@ -210,9 +216,6 @@ func (a *Agent) CloseEnvironment(ctx context.Context, req *proto.CloseEnvRequest
env.EnvConfig.Status = environment.StatusClosed

a.EnvPool.RemoveEnv(envConf.Tag)
if err := state.SaveState(a.EnvPool, a.config.StatePath); err != nil {
log.Error().Err(err).Msg("error saving state")
}
return &proto.StatusResponse{Message: "OK"}, nil
}

Expand All @@ -232,15 +235,15 @@ func (a *Agent) AddExercisesToEnv(ctx context.Context, req *proto.ExerciseReques
}

env.M.Lock()
defer env.M.Unlock()

exerDbConfs, err := a.ExClient.GetExerciseByTags(ctx, &eproto.GetExerciseByTagsRequest{Tag: req.Exercises})
if err != nil {
return nil, fmt.Errorf("error getting exercises: %s", err)
}
defer func() {
env.M.Unlock()
if err := state.SaveState(a.EnvPool, a.config.StatePath); err != nil {
log.Error().Err(err).Msg("error saving state")
}
}()
// Unpack into exercise slice
var exerConfs []exercise.ExerciseConfig
for _, e := range exerDbConfs.Exercises {
for _, e := range req.ExerciseConfigs {
ex, err := protobufToJson(e)
if err != nil {
return nil, err
Expand Down Expand Up @@ -273,12 +276,18 @@ func (a *Agent) AddExercisesToEnv(ctx context.Context, req *proto.ExerciseReques
})
}
wg.Wait()
if err := state.SaveState(a.EnvPool, a.config.StatePath); err != nil {
log.Error().Err(err).Msg("error saving state")
}
return &proto.StatusResponse{Message: "OK"}, nil
}

// Lists currently running, starting and closing environments.
func (a *Agent) ListEnvironments(ctx context.Context, req *proto.Empty) (*proto.ListEnvResponse, error) {
return &proto.ListEnvResponse{
EventTags: a.EnvPool.GetEnvList(),
StartingEventTags: a.EnvPool.GetStartingEnvs(),
ClosingEventTags: a.EnvPool.GetClosingEnvs(),
}, nil
}

func getVPNIP() (string, error) {
// Get VPN IP address from ip pool
ip, err := vpnIPPool.Get()
Expand Down
Loading

0 comments on commit ef4ceab

Please sign in to comment.