Skip to content

Commit

Permalink
Merge pull request #11 from liamg/liamg-azure-support
Browse files Browse the repository at this point in the history
Add azure support
  • Loading branch information
liamg committed Oct 30, 2019
2 parents 2d675df + 5e858ff commit 96bde99
Show file tree
Hide file tree
Showing 11 changed files with 439 additions and 3 deletions.
3 changes: 2 additions & 1 deletion .gitignore
@@ -1,2 +1,3 @@
/tfsec
/bin
/bin
/.idea
9 changes: 7 additions & 2 deletions README.md
Expand Up @@ -55,11 +55,11 @@ If you're not sure which line to add the comment on, just check the tfsec output

## Included Checks

Currently, checks are mostly limited to AWS resources, though support for more common providers will be added in the coming weeks.
Currently, checks are mostly limited to AWS/Azure resources, though support for more common providers will be added in the coming weeks.

| Code | Provider | Description |
|---------|----------|-------------|
| GEN001 | | Potentially sensitive data stored in "default" value of variable.
| GEN001 | * | Potentially sensitive data stored in "default" value of variable.
| AWS001 | aws | S3 Bucket has an ACL defined which allows public access.
| AWS002 | aws | S3 Bucket does not have logging enabled.
| AWS003 | aws | AWS Classic resource usage.
Expand All @@ -74,6 +74,11 @@ Currently, checks are mostly limited to AWS resources, though support for more c
| AWS012 | aws | A resource has a public IP address.
| AWS013 | aws | Task definition defines sensitive environment variable(s).
| AWS014 | aws | Launch configuration with unencrypted block device.
| AZU001 | azurerm | An inbound network security rule allows traffic from `/0`.
| AZU002 | azurerm | An outbound network security rule allows traffic to `/0`.
| AZU003 | azurerm | Unencrypted managed disk.
| AZU004 | azurerm | Unencrypted data lake store.
| AZU005 | azurerm | Password authentication in use instead of SSH keys.

## Support for older terraform versions

Expand Down
6 changes: 6 additions & 0 deletions example/main.tf
Expand Up @@ -11,4 +11,10 @@ resource "aws_alb_listener" "my-alb-listener"{

resource "aws_db_security_group" "my-group" {

}

resource "azurerm_managed_disk" "source" {
encryption_settings = {
enabled = false
}
}
89 changes: 89 additions & 0 deletions internal/app/tfsec/azurerm_open_network_security_rules_test.go
@@ -0,0 +1,89 @@
package tfsec

import (
"testing"

"github.com/liamg/tfsec/internal/app/tfsec/checks"
)

func Test_AzureOpenNetworkSecurityGroupRule(t *testing.T) {

var tests = []struct {
name string
source string
expectedResultCode checks.Code
}{
{
name: "check azurerm_network_security_rule inbound on 0.0.0.0/0",
source: `
resource "azurerm_network_security_rule" "my-rule" {
direction = "Inbound"
source_address_prefix = "0.0.0.0/0"
}`,
expectedResultCode: checks.AzureOpenInboundNetworkSecurityGroupRule,
},
{
name: "check azurerm_network_security_rule inbound on *",
source: `
resource "azurerm_network_security_rule" "my-rule" {
direction = "Inbound"
source_address_prefix = "*"
}`,
expectedResultCode: checks.AzureOpenInboundNetworkSecurityGroupRule,
},
{
name: "check azurerm_network_security_rule inbound on 0.0.0.0/0 in list",
source: `
resource "azurerm_network_security_rule" "my-rule" {
direction = "Inbound"
source_address_prefixes = ["0.0.0.0/0"]
}`,
expectedResultCode: checks.AzureOpenInboundNetworkSecurityGroupRule,
},
{
name: "check azurerm_network_security_rule inbound on * in list",
source: `
resource "azurerm_network_security_rule" "my-rule" {
direction = "Inbound"
source_address_prefixes = ["*"]
}`,
expectedResultCode: checks.AzureOpenInboundNetworkSecurityGroupRule,
},
{
name: "check azurerm_network_security_rule outbound on 0.0.0.0/0",
source: `
resource "azurerm_network_security_rule" "my-rule" {
direction = "Outbound"
destination_address_prefix = "0.0.0.0/0"
}`,
expectedResultCode: checks.AzureOpenOutboundNetworkSecurityGroupRule,
},
{
name: "check azurerm_network_security_rule outbound on 0.0.0.0/0 in list",
source: `
resource "azurerm_network_security_rule" "my-rule" {
direction = "Outbound"
destination_address_prefixes = ["0.0.0.0/0"]
}`,
expectedResultCode: checks.AzureOpenOutboundNetworkSecurityGroupRule,
},
{
name: "check azurerm_network_security_rule outbound on 10.0.0.0/16",
source: `
resource "azurerm_network_security_rule" "my-rule" {
direction = "Outbound"
destination_address_prefix = "10.0.0.0/16"
}`,
expectedResultCode: checks.None,
},

}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
results := scanSource(test.source)
assertCheckCodeExists(t, test.expectedResultCode, results)
})
}

}
50 changes: 50 additions & 0 deletions internal/app/tfsec/azurerm_unencrypted_data_lake_store_test.go
@@ -0,0 +1,50 @@
package tfsec

import (
"testing"

"github.com/liamg/tfsec/internal/app/tfsec/checks"
)

func Test_AzureUnencryptedDataLakeStore(t *testing.T) {

var tests = []struct {
name string
source string
expectedResultCode checks.Code
}{
{
name: "check azurerm_data_lake_store with encryption disabled",
source: `
resource "azurerm_data_lake_store" "my-lake-store" {
encryption_state = "Disabled"
}`,
expectedResultCode: checks.AzureUnencryptedDataLakeStore,
},
{
name: "check azurerm_data_lake_store with encryption enabled",
source: `
resource "azurerm_data_lake_store" "my-lake-store" {
encryption_state = "Enabled"
}`,
expectedResultCode: checks.None,
},
{
name: "check azurerm_data_lake_store with encryption enabled by default",
source: `
resource "azurerm_data_lake_store" "my-lake-store" {
}`,
expectedResultCode: checks.None,
},

}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
results := scanSource(test.source)
assertCheckCodeExists(t, test.expectedResultCode, results)
})
}

}
53 changes: 53 additions & 0 deletions internal/app/tfsec/azurerm_unencrypted_managed_disk_test.go
@@ -0,0 +1,53 @@
package tfsec

import (
"testing"

"github.com/liamg/tfsec/internal/app/tfsec/checks"
)

func Test_AzureUnencryptedManagedDisk(t *testing.T) {

var tests = []struct {
name string
source string
expectedResultCode checks.Code
}{
{
name: "check azurerm_managed_disk with no encryption_settings",
source: `
resource "azurerm_managed_disk" "my-disk" {
}`,
expectedResultCode: checks.AzureUnencryptedManagedDisk,
},
{
name: "check azurerm_managed_disk with encryption disabled",
source: `
resource "azurerm_managed_disk" "my-disk" {
encryption_settings = {
enabled = false
}
}`,
expectedResultCode: checks.AzureUnencryptedManagedDisk,
},
{
name: "check azurerm_managed_disk with encryption enabled",
source: `
resource "azurerm_managed_disk" "my-disk" {
encryption_settings = {
enabled = true
}
}`,
expectedResultCode: checks.None,
},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
results := scanSource(test.source)
assertCheckCodeExists(t, test.expectedResultCode, results)
})
}

}
@@ -0,0 +1,45 @@
package tfsec

import (
"testing"

"github.com/liamg/tfsec/internal/app/tfsec/checks"
)

func Test_AzureVMWithPasswordAuth(t *testing.T) {

var tests = []struct {
name string
source string
expectedResultCode checks.Code
}{
{
name: "check azurerm_virtual_machine with password auth",
source: `
resource "azurerm_virtual_machine" "my-disk" {
os_profile_linux_config = {
disable_password_authentication = false
}
}`,
expectedResultCode: checks.AzureVMWithPasswordAuthentication,
},
{
name: "check azurerm_virtual_machine without password auth",
source: `
resource "azurerm_virtual_machine" "my-disk" {
os_profile_linux_config = {
disable_password_authentication = true
}
}`,
expectedResultCode: checks.None,
},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
results := scanSource(test.source)
assertCheckCodeExists(t, test.expectedResultCode, results)
})
}

}
68 changes: 68 additions & 0 deletions internal/app/tfsec/checks/azurerm_open_network_security_rules.go
@@ -0,0 +1,68 @@
package checks

import (
"fmt"
"strings"

"github.com/hashicorp/hcl/v2"
)

const AzureOpenInboundNetworkSecurityGroupRule Code = "AZU001"
const AzureOpenOutboundNetworkSecurityGroupRule Code = "AZU002"


func init() {
RegisterCheck(Check{
RequiredTypes: []string{"resource"},
RequiredLabels: []string{"azurerm_network_security_rule"},
CheckFunc: func(block *hcl.Block, ctx *hcl.EvalContext) []Result {

directionVal, _, exists := getAttribute(block, ctx, "direction")
if !exists {
return nil
}

code := AzureOpenInboundNetworkSecurityGroupRule
checkAttribute := "source_address_prefix"
if directionVal.AsString() == "Outbound" {
code = AzureOpenOutboundNetworkSecurityGroupRule
checkAttribute = "destination_address_prefix"
}

if prefix, prefixRange, exists := getAttribute(block, ctx, checkAttribute); exists {
if strings.HasSuffix(prefix.AsString(), "/0") || prefix.AsString() == "*" {
return []Result{
NewResult(
code,
fmt.Sprintf(
"Resource '%s' defines a fully open %s network security group rule.",
getBlockName(block),
strings.ToLower(directionVal.AsString()),
),
prefixRange,
),
}
}
}

var results []Result

if prefixesVal, prefixesRange, exists := getAttribute(block, ctx, checkAttribute+"es"); exists {
for _, prefix := range prefixesVal.AsValueSlice() {
if strings.HasSuffix(prefix.AsString(), "/0") || prefix.AsString() == "*"{
results = append(results,
NewResult(
code,
fmt.Sprintf("Resource '%s' defines a fully open %s security group rule.", getBlockName(block), prefix.AsString()),
prefixesRange,
),
)
}
}

}

return results
},
})
}
33 changes: 33 additions & 0 deletions internal/app/tfsec/checks/azurerm_unencrypted_data_lake_store.go
@@ -0,0 +1,33 @@
package checks

import (
"fmt"
"github.com/hashicorp/hcl/v2"
"github.com/zclconf/go-cty/cty"
)

const AzureUnencryptedDataLakeStore Code = "AZU004"

func init() {
RegisterCheck(Check{
RequiredTypes: []string{"resource"},
RequiredLabels: []string{"azurerm_data_lake_store"},
CheckFunc: func(block *hcl.Block, ctx *hcl.EvalContext) []Result {

if encryptionStateVal, encryptionStateRange, exists := getAttribute(block, ctx, "encryption_state"); exists && encryptionStateVal.Type() == cty.String && encryptionStateVal.AsString() == "Disabled" {
return []Result{
NewResult(
AzureUnencryptedDataLakeStore,
fmt.Sprintf(
"Resource '%s' defines an unencrypted data lake store.",
getBlockName(block),
),
encryptionStateRange,
),
}
}

return nil
},
})
}

0 comments on commit 96bde99

Please sign in to comment.