Skip to content
Snippets Groups Projects
Select Git revision
  • 566d37ad119ef8c178b7ea280fdad2e801f3eb74
  • main default
2 results

collector.go

Blame
  • collector.go 6.99 KiB
    // SPDX-License-Identifier: Apache-2.0
    
    // Copyright 2019-2022 Fraunhofer AISEC
    //
    // Licensed under the Apache License, Version 2.0 (the "License");
    // you may not use this file except in compliance with the License.
    // You may obtain a copy of the License at
    //
    //     http://www.apache.org/licenses/LICENSE-2.0
    //
    // Unless required by applicable law or agreed to in writing, software
    // distributed under the License is distributed on an "AS IS" BASIS,
    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    // See the License for the specific language governing permissions and
    // limitations under the License.
    //
    //    $$\      $$\ $$$$$$$$\ $$$$$$$\  $$$$$$\ $$\   $$\  $$$$$$\
    //    $$$\    $$$ |$$  _____|$$  __$$\ \_$$  _|$$$\  $$ |$$  __$$\
    //    $$$$\  $$$$ |$$ |      $$ |  $$ |  $$ |  $$$$\ $$ |$$ /  $$ |
    //    $$\$$\$$ $$ |$$$$$\    $$ |  $$ |  $$ |  $$ $$\$$ |$$$$$$$$ |
    //    $$ \$$$  $$ |$$  __|   $$ |  $$ |  $$ |  $$ \$$$$ |$$  __$$ |
    //    $$ |\$  /$$ |$$ |      $$ |  $$ |  $$ |  $$ |\$$$ |$$ |  $$ |
    //    $$ | \_/ $$ |$$$$$$$$\ $$$$$$$  |$$$$$$\ $$ | \$$ |$$ |  $$ |
    //    \__|     \__|\________|\_______/ \______|\__|  \__|\__|  \__|
    //
    // This file is part of the MEDINA Framework.
    
    package main
    
    import (
    	"collector"
    	"context"
    	"encoding/json"
    	"errors"
    	"fmt"
    	"net"
    	"net/http"
    	"os"
    
    	"clouditor.io/clouditor/api/discovery"
    	"clouditor.io/clouditor/logging/formatter"
    	"clouditor.io/clouditor/rest"
    	"clouditor.io/clouditor/service"
    	service_discovery "clouditor.io/clouditor/service/discovery"
    	"clouditor.io/clouditor/voc"
    	structpb "github.com/golang/protobuf/ptypes/struct"
    	grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
    	grpc_auth "github.com/grpc-ecosystem/go-grpc-middleware/auth"
    	grpc_logrus "github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus"
    	grpc_ctxtags "github.com/grpc-ecosystem/go-grpc-middleware/tags"
    	"github.com/sirupsen/logrus"
    	"golang.org/x/oauth2/clientcredentials"
    	"google.golang.org/grpc"
    	"google.golang.org/grpc/reflection"
    )
    
    var (
    	log              *logrus.Entry
    	server           *grpc.Server
    	discoveryService discovery.DiscoveryServer
    	assessmentUrl    string
    	jwksURL          string
    	config           clientcredentials.Config
    )
    
    const (
    	grpcPort             = 9091
    	httpPort             = 8081
    	AssessmentUrl        = "ASSESSMENT_URL"
    	DefaultAssessmentURL = "localhost:9092"
    	OAuth2ClientID       = "OAUTH2_CLIENT_ID"
    	OAuth2ClientSecret   = "OAUTH2_CLIENT_SECRET"
    	OAuth2TokenURL       = "OAUTH2_TOKEN_URL"
    	JWKSURL              = "AUTH_JWKS_URL"
    )
    
    func toStruct(r voc.IsCloudResource) (s *structpb.Value) {
    	var (
    		b   []byte
    		err error
    	)
    
    	s = new(structpb.Value)
    
    	// this is probably not the fastest approach, but this
    	// way, no extra libraries are needed and no extra struct tags
    	// except `json` are required. there is also no significant
    	// speed increase in marshaling the whole resource list, because
    	// we first need to build it out of the map anyway
    	if b, err = json.Marshal(r); err != nil {
    		return
    	}
    	if err = json.Unmarshal(b, &s); err != nil {
    		return
    	}
    	return
    }
    
    func init() {
    	log = logrus.WithField("component", "grpc")
    	logrus.SetLevel(logrus.DebugLevel)
    
    	// Get URL for Clouditor Assessment from env var
    	var ok bool
    	assessmentUrl, ok = os.LookupEnv(AssessmentUrl)
    	if !ok {
    		// If no environment variable available set to default
    		assessmentUrl = DefaultAssessmentURL
    	}
    
    	// Get the JWKS URL of our auth server
    	jwksURL, _ = os.LookupEnv(JWKSURL)
    
    	// Get the OAuth credentials
    	config = clientcredentials.Config{}
    	config.ClientID, _ = os.LookupEnv(OAuth2ClientID)
    	config.ClientSecret, _ = os.LookupEnv(OAuth2ClientSecret)
    	config.TokenURL, _ = os.LookupEnv(OAuth2TokenURL)
    }
    
    func main() {
    	var textFormatter = logrus.TextFormatter{ForceColors: false, FullTimestamp: true}
    	log.Logger.Formatter = &textFormatter
    
    	fmt.Printf(`
    	$$\      $$\ $$$$$$$$\ $$$$$$$\  $$$$$$\ $$\   $$\  $$$$$$\                                                           
    	$$$\    $$$ |$$  _____|$$  __$$\ \_$$  _|$$$\  $$ |$$  __$$\                                                          
    	$$$$\  $$$$ |$$ |      $$ |  $$ |  $$ |  $$$$\ $$ |$$ /  $$ |                                                         
    	$$\$$\$$ $$ |$$$$$\    $$ |  $$ |  $$ |  $$ $$\$$ |$$$$$$$$ |                                                         
    	$$ \$$$  $$ |$$  __|   $$ |  $$ |  $$ |  $$ \$$$$ |$$  __$$ |                                                         
    	$$ |\$  /$$ |$$ |      $$ |  $$ |  $$ |  $$ |\$$$ |$$ |  $$ |                                                         
    	$$ | \_/ $$ |$$$$$$$$\ $$$$$$$  |$$$$$$\ $$ | \$$ |$$ |  $$ |                                                         
    	\__|     \__|\________|\_______/ \______|\__|  \__|\__|  \__| 
    
    	Evidence Collector 1.1 based on Clouditor framework %s
    	`, collector.ClouditorVersion())
    
    	log.Infof("Security Assessment URL is set to %s", assessmentUrl)
    
    	discoveryService = service_discovery.NewService(
    		service_discovery.WithOAuth2Authorizer(&config),
    		service_discovery.WithProviders([]string{service_discovery.ProviderAzure}),
    		service_discovery.WithAssessmentAddress(assessmentUrl),
    	)
    
    	// Comment in if evidence collector should collect the evidences from the CSPs. Otherwise, example evidences are used.
    	//Start evidence collector
    	_, err := discoveryService.Start(context.Background(), &discovery.StartDiscoveryRequest{})
    	if err != nil {
    		log.Errorf("could not collect evidences: %v", err)
    	}
    
    	grpcLogger := logrus.New()
    	grpcLogger.Formatter = &formatter.GRPCFormatter{TextFormatter: textFormatter}
    	grpcLoggerEntry := grpcLogger.WithField("component", "grpc")
    
    	// create a new socket for gRPC communication
    	sock, err := net.Listen("tcp", fmt.Sprintf(":%d", grpcPort))
    	if err != nil {
    		log.Errorf("could not listen: %v", err)
    	}
    
    	authConfig := service.ConfigureAuth(service.WithJWKSURL(jwksURL))
    	defer authConfig.Jwks.EndBackground()
    
    	server = grpc.NewServer(
    		grpc_middleware.WithUnaryServerChain(
    			grpc_ctxtags.UnaryServerInterceptor(grpc_ctxtags.WithFieldExtractor(grpc_ctxtags.CodeGenRequestFieldExtractor)),
    			grpc_logrus.UnaryServerInterceptor(grpcLoggerEntry),
    			grpc_auth.UnaryServerInterceptor(authConfig.AuthFunc),
    		),
    		grpc_middleware.WithStreamServerChain(
    			grpc_ctxtags.StreamServerInterceptor(grpc_ctxtags.WithFieldExtractor(grpc_ctxtags.CodeGenRequestFieldExtractor)),
    			grpc_logrus.StreamServerInterceptor(grpcLoggerEntry),
    			grpc_auth.StreamServerInterceptor(authConfig.AuthFunc),
    		))
    
    	discovery.RegisterDiscoveryServer(server, discoveryService)
    	// enable reflection, primary for testing in early stages
    	reflection.Register(server)
    
    	// start the gRPC-HTTP gateway
    	go func() {
    		err = rest.RunServer(context.Background(), grpcPort, httpPort)
    		if errors.Is(err, http.ErrServerClosed) {
    			os.Exit(0)
    			return
    		}
    
    		if err != nil {
    			log.Fatalf("failed to serve gRPC-HTTP gateway: %v", err)
    		}
    	}()
    
    	log.Infof("Starting gRPC endpoint on :%d", grpcPort)
    
    	// serve the gRPC socket
    	if err := server.Serve(sock); err != nil {
    		log.Infof("failed to serve gRPC endpoint: %s", err)
    		return
    	}
    }