-
Notifications
You must be signed in to change notification settings - Fork 553
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 0bacbd9
Showing
56 changed files
with
9,205 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
netmaker | ||
netclient/netclient | ||
netclient/files/netclient |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
#first stage - builder | ||
|
||
FROM golang:1.14-stretch as builder | ||
|
||
COPY . /app | ||
|
||
WORKDIR /app | ||
|
||
ENV GO111MODULE=auto | ||
|
||
RUN CGO_ENABLED=0 GOOS=linux go build -o app main.go | ||
|
||
|
||
#second stage | ||
|
||
FROM alpine:latest | ||
|
||
WORKDIR /root/ | ||
|
||
RUN apk add --no-cache tzdata | ||
|
||
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ | ||
|
||
COPY --from=builder /app . | ||
COPY --from=builder /app/config config | ||
|
||
EXPOSE 8081 | ||
EXPOSE 50051 | ||
|
||
CMD ["./app"] | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
|
||
<p align="center"> | ||
<img src="netmaker.png"><break/> | ||
</p> | ||
<p align="center"> | ||
<i>Connect any computers together over a secure, fast, private network, and manage multiple networks from a central server.</i> | ||
</p> | ||
|
||
## What is Netmaker? | ||
Netmaker lets you easily create secure virtual networks: Just spin up a Netmaker server and install the agent on your computers. Netmaker relies on WireGuard to create encrypted tunnels between every node in your virtual network, creating a mesh overlay. Netmaker takes the work out of manually configuring machines and updating them every time something changes in your network. The agents are self-updating and pull necessary changes from the server. | ||
|
||
Netmaker also has a handy dandy UI, which you can find in [this repo](https://github.com/falconcat-inc/WireCat-UI). We recommend deploying the UI alongside the server to make the experience easier and better. | ||
|
||
## Why Netmaker? | ||
1. Create a flat, secure network between multiple/hybrid cloud environments | ||
2. Integrate central and edge services + IoT | ||
3. Secure an office or home network while providing remote connectivity | ||
4. Manage cryptocurrency proof-of-stake machines | ||
5. Provide an additional layer of security on an existing network | ||
6. Encrypt Kubernetes inter-node communications | ||
7. Secure site-to-site connections | ||
|
||
<p align="center"> | ||
<img src="mesh-diagram.png"> | ||
</p> | ||
|
||
## Docs | ||
**For more information, please read the docs, or check out the Quick Start below:** | ||
|
||
- [Getting Started](docs/GETTING_STARTED.md) | ||
- [API Documentation](docs/API.md) | ||
- [Product Roadmap](docs/ROADMAP.md) | ||
- [Contributing](docs/CONTRIBUTING.md) | ||
|
||
|
||
## Quick Start | ||
|
||
Setup Docker (Prereq): | ||
1. Create an access token on github with artifact access. | ||
2. On your VPS, create a file in the home dir called TOKEN.txt with the value of your token inside. | ||
3. `cat ~/TOKEN.txt | sudo docker login https://docker.pkg.github.com -u GITHUB_USERNAME --password-stdin` | ||
|
||
Setup Server: | ||
1. Clone this repo or just copy contents of "docker-compose.yml" to a machine with a public IP. | ||
2. In docker-compose.yml, change BACKEND_URL to the public IP ofthat machine. | ||
3. Run `sudo docker-compose up` | ||
4. Navigate to your IP and you should see the WireCat UI asking for a new admin user (if not or if it takes you straight to login screen without asking for user creation, investigate the error). | ||
5. Create the admin user | ||
6. Click "Create Group" and fill out the details (group == network) | ||
7. You are now ready to begin using WireCat. Create a key or "allow manual node sign up." | ||
|
||
Run on each machine in network: | ||
1. Get the binary: `sudo wget 52.55.6.84:8081/meshclient/files/meshclient` | ||
2. Make it executable: `sudo chmod +x meshclient` | ||
3. Run the install command: `sudo ./meshclient -c install -g <group name> -s <server:port> -k <key value>` | ||
|
||
|
||
#### LICENSE | ||
|
||
Netmaker's source code and all artifacts in this repository are freely available. All versions are published under the Server Side Public License (SSPL), version 1, which can be found under the "licensing" directory: [LICENSE.txt](licensing/LICENSE.txt). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
//Environment file for getting variables | ||
//Currently the only thing it does is set the master password | ||
//Should probably have it take over functions from OS such as port and mongodb connection details | ||
//Reads from the config/environments/dev.yaml file by default | ||
//TODO: Add vars for mongo and remove from OS vars in mongoconn | ||
package config | ||
|
||
import ( | ||
"os" | ||
"fmt" | ||
"log" | ||
"gopkg.in/yaml.v3" | ||
) | ||
|
||
//setting dev by default | ||
func getEnv() string { | ||
|
||
env := os.Getenv("APP_ENV") | ||
|
||
if len(env) == 0 { | ||
return "dev" | ||
} | ||
|
||
return env | ||
} | ||
|
||
// Config : application config stored as global variable | ||
var Config *EnvironmentConfig | ||
|
||
// EnvironmentConfig : | ||
type EnvironmentConfig struct { | ||
Server ServerConfig `yaml:"server"` | ||
MongoConn MongoConnConfig `yaml:"mongoconn"` | ||
} | ||
|
||
// ServerConfig : | ||
type ServerConfig struct { | ||
Host string `yaml:"host"` | ||
ApiPort string `yaml:"apiport"` | ||
GrpcPort string `yaml:"grpcport"` | ||
MasterKey string `yaml:"masterkey"` | ||
AllowedOrigin string `yaml:"allowedorigin"` | ||
RestBackend bool `yaml:"restbackend"` | ||
AgentBackend bool `yaml:"agentbackend"` | ||
} | ||
|
||
type MongoConnConfig struct { | ||
User string `yaml:"user"` | ||
Pass string `yaml:"pass"` | ||
Host string `yaml:"host"` | ||
Port string `yaml:"port"` | ||
Opts string `yaml:"opts"` | ||
} | ||
|
||
|
||
//reading in the env file | ||
func readConfig() *EnvironmentConfig { | ||
file := fmt.Sprintf("config/environments/%s.yaml", getEnv()) | ||
f, err := os.Open(file) | ||
if err != nil { | ||
log.Fatal(err) | ||
os.Exit(2) | ||
} | ||
defer f.Close() | ||
|
||
var cfg EnvironmentConfig | ||
decoder := yaml.NewDecoder(f) | ||
err = decoder.Decode(&cfg) | ||
if err != nil { | ||
log.Fatal(err) | ||
os.Exit(2) | ||
} | ||
return &cfg | ||
|
||
} | ||
|
||
func init() { | ||
Config = readConfig() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
server: | ||
host: "localhost" | ||
apiport: "8081" | ||
grpcport: "50051" | ||
masterkey: "secretkey" | ||
allowedorigin: "*" | ||
restbackend: true | ||
agentbackend: true | ||
mongoconn: | ||
user: "mongoadmin" | ||
pass: "mongopass" | ||
host: "localhost" | ||
port: "27017" | ||
opts: '/?authSource=admin' |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,154 @@ | ||
package controller | ||
|
||
import ( | ||
"errors" | ||
"context" | ||
"golang.org/x/crypto/bcrypt" | ||
"time" | ||
nodepb "github.com/gravitl/netmaker/grpc" | ||
"github.com/gravitl/netmaker/models" | ||
"github.com/gravitl/netmaker/functions" | ||
"github.com/gravitl/netmaker/mongoconn" | ||
"go.mongodb.org/mongo-driver/bson" | ||
"google.golang.org/grpc" | ||
"google.golang.org/grpc/metadata" | ||
"google.golang.org/grpc/status" | ||
"google.golang.org/grpc/codes" | ||
|
||
) | ||
|
||
func AuthServerUnaryInterceptor(ctx context.Context, | ||
req interface{}, | ||
info *grpc.UnaryServerInfo, | ||
handler grpc.UnaryHandler) (interface{}, error) { | ||
// Skip authorize when GetJWT is requested | ||
|
||
if info.FullMethod != "/node.NodeService/Login" { | ||
if info.FullMethod != "/node.NodeService/CreateNode" { | ||
|
||
err := grpcAuthorize(ctx) | ||
if err != nil { | ||
return nil, err | ||
} | ||
} | ||
} | ||
|
||
|
||
// Calls the handler | ||
h, err := handler(ctx, req) | ||
|
||
return h, err | ||
} | ||
func AuthServerStreamInterceptor( | ||
srv interface{}, | ||
stream grpc.ServerStream, | ||
info *grpc.StreamServerInfo, | ||
handler grpc.StreamHandler, | ||
) error { | ||
if info.FullMethod == "/node.NodeService/GetPeers" { | ||
if err := grpcAuthorize(stream.Context()); err != nil { | ||
return err | ||
} | ||
} | ||
|
||
|
||
// Calls the handler | ||
return handler(srv, stream) | ||
} | ||
|
||
func grpcAuthorize(ctx context.Context) error { | ||
|
||
|
||
md, ok := metadata.FromIncomingContext(ctx) | ||
|
||
if !ok { | ||
return status.Errorf(codes.InvalidArgument, "Retrieving metadata is failed") | ||
} | ||
|
||
authHeader, ok := md["authorization"] | ||
if !ok { | ||
return status.Errorf(codes.Unauthenticated, "Authorization token is not supplied") | ||
} | ||
|
||
authToken := authHeader[0] | ||
|
||
mac, group, err := functions.VerifyToken(authToken) | ||
|
||
if err != nil { return err } | ||
|
||
groupexists, err := functions.GroupExists(group) | ||
|
||
if err != nil { | ||
return err | ||
} | ||
emptynode := models.Node{} | ||
node, err := functions.GetNodeByMacAddress(group, mac) | ||
if err != nil || node == emptynode { | ||
return status.Errorf(codes.Unauthenticated, "Node does not exist.") | ||
} | ||
|
||
//check that the request is for a valid group | ||
//if (groupCheck && !groupexists) || err != nil { | ||
if (!groupexists) { | ||
|
||
return status.Errorf(codes.Unauthenticated, "Group does not exist.") | ||
|
||
} else { | ||
return nil | ||
} | ||
} | ||
|
||
|
||
//Node authenticates using its password and retrieves a JWT for authorization. | ||
func (s *NodeServiceServer) Login(ctx context.Context, req *nodepb.LoginRequest) (*nodepb.LoginResponse, error) { | ||
|
||
//out := new(LoginResponse) | ||
macaddress := req.GetMacaddress() | ||
password := req.GetPassword() | ||
|
||
var result models.NodeAuth | ||
|
||
err := errors.New("Generic server error.") | ||
|
||
|
||
if macaddress == "" { | ||
//TODO: Set Error response | ||
err = errors.New("Missing Mac Address.") | ||
return nil, err | ||
} else if password == "" { | ||
err = errors.New("Missing Password.") | ||
return nil, err | ||
} else { | ||
//Search DB for node with Mac Address. Ignore pending nodes (they should not be able to authenticate with API untill approved). | ||
collection := mongoconn.Client.Database("wirecat").Collection("nodes") | ||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) | ||
var err = collection.FindOne(ctx, bson.M{ "macaddress": macaddress, "ispending": false }).Decode(&result) | ||
|
||
defer cancel() | ||
|
||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
//compare password from request to stored password in database | ||
//might be able to have a common hash (certificates?) and compare those so that a password isn't passed in in plain text... | ||
//TODO: Consider a way of hashing the password client side before sending, or using certificates | ||
err = bcrypt.CompareHashAndPassword([]byte(result.Password), []byte(password)) | ||
if err != nil && result.Password != password { | ||
return nil, err | ||
} else { | ||
//Create a new JWT for the node | ||
tokenString, _ := functions.CreateJWT(macaddress, result.Group) | ||
|
||
if tokenString == "" { | ||
err = errors.New("Something went wrong. Could not retrieve token.") | ||
return nil, err | ||
} | ||
|
||
response := &nodepb.LoginResponse{ | ||
Accesstoken: tokenString, | ||
} | ||
return response, nil | ||
} | ||
} | ||
} |
Oops, something went wrong.