Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hackaton export formats #55

Open
wants to merge 25 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
8efa33c
Added command line arguments
Jan 17, 2019
99fbedb
add interfaces for outputs
morfeush22 Jan 17, 2019
150e88f
add csv output
morfeush22 Jan 17, 2019
060cc90
Added support for other formats
Jan 17, 2019
af88e5e
Merge branch 'hackaton-export-formats' of https://github.com/Applisca…
morfeush22 Jan 17, 2019
2d1c11e
Fixed cyclic imports
Jan 17, 2019
2a3ad7d
Moved error handling to specific functions
Jan 17, 2019
b0456fc
update functions body
morfeush22 Jan 17, 2019
6bd0322
Merge branch 'hackaton-export-formats' of https://github.com/Applisca…
morfeush22 Jan 17, 2019
5dcdffd
fix empty csv
morfeush22 Jan 17, 2019
6e760a9
rendering html
morfeush22 Jan 17, 2019
76695fe
Added handling for files and STDOUT in all formats. Cleaned up code
Jan 22, 2019
ee76249
Added Error handling and introduced file handling changes
Jan 22, 2019
e8ce0db
Add report HTML template
MarcinKasprowicz Jan 22, 2019
a827d41
add HTML report template to Go module; rewrite PrintHtmlReport signature
morfeush22 Jan 23, 2019
eec68a8
fix redundant spaces
morfeush22 Jan 23, 2019
c5b41b0
JSON parse in report_html
MarcinKasprowicz Jan 23, 2019
9638359
Check if undefined during parsing
MarcinKasprowicz Jan 23, 2019
8378493
Fix typo
MarcinKasprowicz Jan 23, 2019
34b7563
using correct template type to escape JSON chars
morfeush22 Jan 23, 2019
2060d41
optimize imports
morfeush22 Jan 23, 2019
0ab0e63
Delete asd.html
MarcinKasprowicz Jan 28, 2019
be776fe
Delete report_template.html
MarcinKasprowicz Jan 28, 2019
482e3f3
Merge branch 'master' into hackaton-export-formats
Jan 31, 2019
80001c6
Integrated iAM support
Jan 31, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 53 additions & 1 deletion cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,21 @@ import (
"os"

"github.com/Appliscale/cloud-security-audit/configuration"
"github.com/Appliscale/cloud-security-audit/resource"
"github.com/Appliscale/cloud-security-audit/csasession"
"github.com/Appliscale/cloud-security-audit/resource"

"github.com/Appliscale/cloud-security-audit/environment"
"github.com/Appliscale/cloud-security-audit/report"
"github.com/Appliscale/cloud-security-audit/scanner"
"github.com/spf13/cobra"
"strings"
)

// var cfgFile string
var config = configuration.GetConfig()

const STDOUT = "stdout"

// rootCmd represents the base command when called without any subcommands
var rootCmd = &cobra.Command{
Use: "cloud-security-audit",
Expand Down Expand Up @@ -45,6 +49,8 @@ var (
profile string
mfa bool
mfaDuration int64
format string
outputFile string
)

func init() {
Expand All @@ -58,6 +64,8 @@ func init() {

rootCmd.Flags().BoolVarP(&mfa, "mfa", "m", false, "indicates usage of Multi Factor Authentication")
rootCmd.Flags().Int64VarP(&mfaDuration, "mfa-duration", "d", 0, "sets the duration of the MFA session")
rootCmd.Flags().StringVarP(&format, "format", "f", "TABLE", "specifies output format, available are: JSON, HTML, CSV, TABLE")
rootCmd.Flags().StringVarP(&outputFile, "output", "o", "STDOUT", "specify output file")
}

func getRegions() *[]string {
Expand Down Expand Up @@ -88,10 +96,54 @@ func getProfile() string {
return "default"
}

var printFormats = map[string]func(report.Report, *os.File){"TABLE": report.PrintTable, "JSON": report.PrintJsonReport, "HTML": report.PrintHtmlReport, "CSV": report.PrintCSVReport}

func getFormat() func(report.Report, *os.File) {
for formatName, formatValue := range printFormats {
if format == formatName {
return formatValue
}
}
config.Logger.Error("Wrong type: " + format + " Available are: TABLE, JSON, HTML, CSV. Using default: TABLE")
return report.PrintTable
}

func getOutputFile() *os.File {
var ans string
if strings.ToLower(outputFile) == STDOUT {
return os.Stdout
}

if _, err := os.Stat(outputFile); err == nil {
config.Logger.GetInput("file "+outputFile+" already exists. Do you want to override it? [Y/n]", &ans)
if strings.ToLower(ans) == "y" || strings.ToLower(ans) == "yes" || ans == "" {
f, err := os.Create(outputFile)
if err != nil {
panic(err)
}
return f
} else {
os.Exit(1)
}
} else if os.IsNotExist(err) {
f, err := os.Create(outputFile)
if err != nil {
os.Exit(1)
}
return f
} else {
config.Logger.Error("Cannot determine if file " + outputFile + " exists")
os.Exit(1)
}
return os.Stdout
}

func initConfig() {
config.Regions = getRegions()
config.Services = getServices()
config.Profile = getProfile()
config.PrintFormat = getFormat()
config.OutputFile = getOutputFile()
config.Mfa = mfa
config.MfaDuration = mfaDuration
configuration.InitialiseMFA(config)
Expand Down
6 changes: 5 additions & 1 deletion configuration/config.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package configuration

import (
"github.com/Appliscale/cloud-security-audit/logger"
"github.com/Appliscale/cloud-security-audit/csasession/clientfactory"
"github.com/Appliscale/cloud-security-audit/csasession/sessionfactory"
"github.com/Appliscale/cloud-security-audit/logger"
"github.com/Appliscale/cloud-security-audit/report"
"os"
)

type Config struct {
Expand All @@ -15,6 +17,8 @@ type Config struct {
Logger *logger.Logger
Mfa bool
MfaDuration int64
PrintFormat func(report.Report, *os.File)
OutputFile *os.File
}

func GetConfig() (config Config) {
Expand Down
2 changes: 1 addition & 1 deletion configuration/config_mocks.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package configuration

import (
"github.com/Appliscale/cloud-security-audit/logger"
"github.com/Appliscale/cloud-security-audit/csasession/clientfactory/mocks"
"github.com/Appliscale/cloud-security-audit/csasession/sessionfactory"
"github.com/Appliscale/cloud-security-audit/logger"
"testing"
)

Expand Down
2 changes: 1 addition & 1 deletion environment/checkfiles.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ package environment

import (
"bufio"
"github.com/Appliscale/perun/helpers"
"github.com/Appliscale/cloud-security-audit/configuration"
"github.com/Appliscale/perun/helpers"
"os"
"strconv"
"strings"
Expand Down
2 changes: 1 addition & 1 deletion environment/createfiles.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ package environment

import (
"fmt"
"github.com/Appliscale/perun/helpers"
"github.com/Appliscale/cloud-security-audit/configuration"
"github.com/Appliscale/perun/helpers"
"os"
"strings"
)
Expand Down
35 changes: 31 additions & 4 deletions report/report.go
Original file line number Diff line number Diff line change
@@ -1,25 +1,52 @@
package report

import (
"github.com/Appliscale/cloud-security-audit/logger"
"github.com/olekukonko/tablewriter"
"os"
"strings"
)

var ReportLogger = logger.CreateDefaultLogger()

type Report interface {
FormatDataToTable() [][]string
GetHeaders() []string
GetTableHeaders() []string
GetJsonReport() []byte
PrintHtmlReport(*os.File) error
GetCsvReport() []byte
}

func handleOutput(output []byte, file *os.File) {
out := append(output, []byte("\n\n")...)
_, err := file.Write(out)
if err != nil {
panic(err)
}
file.Sync()
}

func PrintJsonReport(r Report, filename *os.File) {
handleOutput(r.GetJsonReport(), filename)
}

func PrintHtmlReport(r Report, filename *os.File) {
r.PrintHtmlReport(filename)
}

func PrintCSVReport(r Report, filename *os.File) {
handleOutput(r.GetCsvReport(), filename)
}

func PrintTable(r Report) {
func PrintTable(r Report, file *os.File) {

data := r.FormatDataToTable()

table := tablewriter.NewWriter(os.Stdout)
table := tablewriter.NewWriter(file)
// Configure Headers
table.SetReflowDuringAutoWrap(false)
table.SetAutoFormatHeaders(false)
table.SetHeader(customFormatHeaders(r.GetHeaders()))
table.SetHeader(customFormatHeaders(r.GetTableHeaders()))
// Configure rows&cells
table.SetRowSeparator("-")
table.SetRowLine(true)
Expand Down
5 changes: 5 additions & 0 deletions report/resourceReports/csv_report.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package resourceReports

type CsvReport interface {
GetCsvReport() ([]byte, error)
}
80 changes: 71 additions & 9 deletions report/ec2report.go → report/resourceReports/ec2report.go
Original file line number Diff line number Diff line change
@@ -1,21 +1,26 @@
package report
package resourceReports

import (
"bytes"
"encoding/json"
"fmt"
"github.com/Appliscale/cloud-security-audit/configuration"
"github.com/Appliscale/cloud-security-audit/environment"
"github.com/Appliscale/cloud-security-audit/report"
"github.com/Appliscale/cloud-security-audit/resource"
"html/template"
"os"
"sort"
"strconv"
"strings"
)

type Ec2Report struct {
VolumeReport *VolumeReport
InstanceID string
SortableTags *SortableTags
SecurityGroupsIDs []string
AvailabilityZone string
VolumeReport *VolumeReport `json:"volume_report"`
InstanceID string `json:"instance_id"`
SortableTags *SortableTags `json:"sortable_tags"`
SecurityGroupsIDs []string `json:"security_groups_ids"`
AvailabilityZone string `json:"availability_zone"`
}

func NewEc2Report(instanceID string) *Ec2Report {
Expand All @@ -36,7 +41,64 @@ type Ec2ReportRequiredResources struct {
AvailabilityZone string
}

func (e *Ec2Reports) GetHeaders() []string {
func (e Ec2Reports) GetJsonReport() []byte {
output, err := json.Marshal(e)
if err == nil {
return output
}
report.ReportLogger.Error("Error generating Json report")
os.Exit(1)
return []byte{}
}

func (e Ec2Reports) PrintHtmlReport(outputFile *os.File) error {
data := e.GetJsonReport()
reportTemplate := GetHtmlTemplate()

tmpl, err := template.New("report_template").Parse(reportTemplate)
if err != nil {
report.ReportLogger.Error("Can not parse reportTemplate")
}

err = tmpl.Execute(outputFile, map[string]string{"EC2_JSON_PLACEHOLDER": string(data)})
if err != nil {
report.ReportLogger.Error("Can not execute reportTemplate")
}

return err
}

func (e Ec2Reports) GetCsvReport() []byte {
const internalSep = ";"
const externalSep = ","

csv := []string{strings.Join([]string{
"\"Availability Zone\"",
"\"EC2\"",
"\"Volumes encrypton\"",
"\"Open Security Groups\"",
"\"EC2 Tags\"",
}, externalSep)}

for _, row := range e {
rowStr := make([]string, 0)

rowStr = append(rowStr, strings.Join(*row.VolumeReport, internalSep))
rowStr = append(rowStr, row.InstanceID)

for tag, val := range row.SortableTags.Tags {
rowStr = append(rowStr, fmt.Sprintf("%s%s%s", tag, internalSep, val))
}

rowStr = append(rowStr, strings.Join(row.SecurityGroupsIDs, internalSep))

csv = append(csv, strings.Join(rowStr, externalSep))
}

return []byte(strings.Join(csv, "\n"))
}

func (e *Ec2Reports) GetTableHeaders() []string {
return []string{"Availability\nZone", "EC2", "Volumes\n(None) - not encrypted\n(DKMS) - encrypted with default KMSKey", "Security\nGroups\n(Incoming CIDR = 0\x2E0\x2E0\x2E0/0)\nID : PROTOCOL : PORT", "EC2 Tags"}
}

Expand Down Expand Up @@ -65,12 +127,12 @@ func (e *Ec2Reports) GenerateReport(r *Ec2ReportRequiredResources) {
volume := r.Volumes.FindById(*blockDeviceMapping.Ebs.VolumeId)
if !*volume.Encrypted {
ec2OK = false
ec2Report.VolumeReport.AddEBS(*volume.VolumeId, NONE)
ec2Report.VolumeReport.AddEBS(*volume.VolumeId, report.NONE)
} else {
kmskey := r.KMSKeys.FindByKeyArn(*volume.KmsKeyId)
if !kmskey.Custom {
ec2OK = false
ec2Report.VolumeReport.AddEBS(*volume.VolumeId, DKMS)
ec2Report.VolumeReport.AddEBS(*volume.VolumeId, report.DKMS)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package report
package resourceReports

import (
"sort"
Expand Down
Loading