Skip to content

Commit

Permalink
Add custom certificate CFN resource (#857)
Browse files Browse the repository at this point in the history
  • Loading branch information
Austin Byers authored May 8, 2020
1 parent 669d6d0 commit 21c1623
Show file tree
Hide file tree
Showing 22 changed files with 573 additions and 384 deletions.
38 changes: 3 additions & 35 deletions deployments/bootstrap.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,6 @@ Description: The very first Panther stack - static resources which don't require
# - The cognito user pool and appsync API

Parameters:
# Required
CertificateArn:
Type: String
Description: The ARN of the TLS certificate that is going to be used by the ALB listener

# Optional
LogSubscriptionPrincipals:
Type: CommaDelimitedList
Expand Down Expand Up @@ -637,33 +632,6 @@ Resources:
IpProtocol: '-1'
SourceSecurityGroupId: !Ref PublicLoadBalancerSecurityGroup

PublicLoadBalancerListener:
Type: AWS::ElasticLoadBalancingV2::Listener
Properties:
Certificates:
- CertificateArn: !Ref CertificateArn
DefaultActions:
- TargetGroupArn: !Ref TargetGroup
Type: forward
LoadBalancerArn: !Ref PublicLoadBalancer
Port: 443
Protocol: HTTPS
SslPolicy: ELBSecurityPolicy-TLS-1-2-Ext-2018-06

# Create a rule on the load balancer for routing traffic to the target group
LoadBalancerRule:
Type: AWS::ElasticLoadBalancingV2::ListenerRule
Properties:
Actions:
- Type: forward
TargetGroupArn: !Ref TargetGroup
Conditions:
- Field: path-pattern
Values:
- '*'
ListenerArn: !Ref PublicLoadBalancerListener
Priority: 1

########## Appsync ##########
AppsyncServiceRole:
Type: AWS::IAM::Role
Expand Down Expand Up @@ -816,15 +784,15 @@ Outputs:
Value: !Ref Source

# Networking + elb
CertificateArn:
Description: The ARN of the TLS certificate used by the ALB listener
Value: !Ref CertificateArn
SubnetOneId:
Description: Public subnet one
Value: !Ref PublicSubnetOne
SubnetTwoId:
Description: Public subnet two
Value: !Ref PublicSubnetTwo
LoadBalancerArn:
Description: Web load balancer arn
Value: !Ref PublicLoadBalancer
LoadBalancerFullName:
Description: Web load balancer full resource name
Value: !GetAtt PublicLoadBalancer.LoadBalancerFullName
Expand Down
83 changes: 75 additions & 8 deletions deployments/bootstrap_gateway.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,27 @@ Description: API gateway and Python layer
# - API gateways: 'mage deploy' embeds swagger definitions directly into this template,
# making the template too large to deploy without an S3 bucket
# - Python layer: the layer source has to be uploaded to S3 before the cfn resource can be created
# - Custom resource: the Lambda function which handles custom CFN resources

Parameters:
# From the config file
CloudWatchLogRetentionDays:
Type: Number
Description: CloudWatch log retention period
Default: 365
LayerVersionArns:
Type: CommaDelimitedList
Description: List of LayerVersion ARNs to attach to each function
Default: ''
PythonLayerVersionArn:
Type: String
Description: Custom Python layer for analysis and remediation
Default: ''
TracingEnabled:
TracingMode:
Type: String
Description: Enable XRay tracing on API Gateway
AllowedValues: [true, false]
Default: false
Description: Enable XRay tracing on Lambda and API Gateway
AllowedValues: ['', Active, PassThrough]
Default: ''

# If no custom layer is provided, 'mage deploy' will have uploaded a layer here:
SourceBucket:
Expand All @@ -52,7 +61,9 @@ Parameters:
Default: ''

Conditions:
AttachLayers: !Not [!Equals [!Join ['', !Ref LayerVersionArns], '']]
CreatePythonLayer: !Equals [!Ref PythonLayerVersionArn, '']
TracingEnabled: !Not [!Equals ['', !Ref TracingMode]]

Resources:
PythonLayer:
Expand All @@ -69,6 +80,62 @@ Resources:
Description: Pip libraries available to the Python analysis/remediation functions
LayerName: panther-analysis

# When deploying from source, the S3 "source" bucket must exist before this function can be packaged.
# That is why this resource is here instead of in the very first "bootstrap" stack.
CustomResourceFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: ../bin/internal/core/custom_resources/main
Description: Custom CloudFormation resources when deploying Panther
Environment:
Variables:
DEBUG: true
FunctionName: panther-cfn-custom-resources
# <cfndoc>
# Used by CloudFormation when deploying or updating Panther.
#
# Failure Impact
# * Panther itself will not be affected, but deployments may be failing
# </cfndoc>
Handler: main
Layers: !If [AttachLayers, !Ref LayerVersionArns, !Ref 'AWS::NoValue']
MemorySize: 256
Runtime: go1.x
Timeout: 900 # Maximum allowed: 15 minutes
Tracing: !If [TracingEnabled, !Ref TracingMode, !Ref 'AWS::NoValue']

# This function has more permissions than usual because it creates and destroys infrastructure.
# It is used only by CloudFormation in the deploy process and not by the Panther application itself.
Policies:
- Id: CertificateManagement
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- acm:AddTagsToCertificate
- acm:DeleteCertificate
- acm:ImportCertificate
- acm:RemoveTagsFromCertificate
# ACM certificate IDs are random and at the time of writing, DeleteCertificate does
# not support using resource tags as a condition.
# So this is as narrow as this resource can get:
Resource: !Sub arn:${AWS::Partition}:acm:${AWS::Region}:${AWS::AccountId}:certificate/*
- Effect: Allow
Action:
- iam:DeleteServerCertificate
- iam:UploadServerCertificate
Resource:
- !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:server-certificate/panther/*
# IAM sometimes requires permissions to match the certificate name, not the full path
# This seems like a bug in IAM, but in any case a fresh deploy/teardown will not work without this:
- !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:server-certificate/Panther*

CustomResourceLogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: /aws/lambda/panther-cfn-custom-resources
RetentionInDays: !Ref CloudWatchLogRetentionDays

AnalysisApi:
Type: AWS::Serverless::Api
Properties:
Expand All @@ -79,7 +146,7 @@ Resources:
# The `panther-analysis-api` API Gateway calls the `panther-analysis-api` lambda.
# </cfndoc>
StageName: v1
TracingEnabled: !Ref TracingEnabled
TracingEnabled: !If [TracingEnabled, true, false]

ComplianceApi:
Type: AWS::Serverless::Api
Expand All @@ -91,7 +158,7 @@ Resources:
# The `panther-compliance-api` API Gateway calls the `panther-compliance-api` lambda.
# </cfndoc>
StageName: v1
TracingEnabled: !Ref TracingEnabled
TracingEnabled: !If [TracingEnabled, true, false]

RemediationApi:
Type: AWS::Serverless::Api
Expand All @@ -103,7 +170,7 @@ Resources:
# The `panther-remediation-api` API Gateway calls the `panther-remediation-api` lambda.
# </cfndoc>
StageName: v1
TracingEnabled: !Ref TracingEnabled
TracingEnabled: !If [TracingEnabled, true, false]

ResourcesApi:
Type: AWS::Serverless::Api
Expand All @@ -115,7 +182,7 @@ Resources:
# The `panther-resources-api` API Gateway calls the `panther-resources-api` lambda.
# </cfndoc>
StageName: v1
TracingEnabled: !Ref TracingEnabled
TracingEnabled: !If [TracingEnabled, true, false]

Outputs:
PythonLayerVersionArn:
Expand Down
48 changes: 47 additions & 1 deletion deployments/web_server.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,16 @@ AWSTemplateFormatVersion: 2010-09-09
Description: The service that defines the front-end NodeJS server that serves the Panther web application statics

Parameters:
# Passed in from bootstrap.yml stack
# Passed in from bootstrap stacks
SubnetOneId:
Type: String
Description: The ID of a subnet in the VPC above
SubnetTwoId:
Type: String
Description: The ID of another subnet in the VPC above
ElbArn:
Type: String
Description: The ARN of the load balancer
ElbTargetGroup:
Type: String
Description: The ARN of the load balancer target group
Expand All @@ -37,6 +40,10 @@ Parameters:
Type: Number
Description: CloudWatch log retention period
Default: 365
CertificateArn:
Type: String
Description: TLS certificate used by the web app. If not specfied, a self-signed cert is created for you.
Default: ''

# Generated in deploy process
Image:
Expand All @@ -56,10 +63,49 @@ Parameters:
Default: 80
Description: The exposed port of the application, that will be used by the VPC & Container

Conditions:
CreateCertificate: !Equals [!Ref CertificateArn, '']

Resources:
SelfSignedCertificate:
Condition: CreateCertificate
Type: Custom::Certificate
Properties:
ServiceToken: !Sub arn:${AWS::Partition}:lambda:${AWS::Region}:${AWS::AccountId}:function:panther-cfn-custom-resources

PublicLoadBalancerListener:
Type: AWS::ElasticLoadBalancingV2::Listener
Properties:
Certificates:
- CertificateArn:
!If [CreateCertificate, !GetAtt SelfSignedCertificate.Arn, !Ref CertificateArn]
DefaultActions:
- TargetGroupArn: !Ref ElbTargetGroup
Type: forward
LoadBalancerArn: !Ref ElbArn
Port: 443
Protocol: HTTPS
SslPolicy: ELBSecurityPolicy-TLS-1-2-Ext-2018-06

# Create a rule on the load balancer for routing traffic to the target group
LoadBalancerRule:
Type: AWS::ElasticLoadBalancingV2::ListenerRule
Properties:
Actions:
- Type: forward
TargetGroupArn: !Ref ElbTargetGroup
Conditions:
- Field: path-pattern
Values:
- '*'
ListenerArn: !Ref PublicLoadBalancerListener
Priority: 1

# The service that will instantiate a server task and restrict access through our ALB
WebApplicationServer:
Type: AWS::ECS::Service
# The cert in the listener can't be deleted until the service has stopped.
DependsOn: PublicLoadBalancerListener
Properties:
Cluster: panther-web-cluster
DeploymentConfiguration:
Expand Down
6 changes: 6 additions & 0 deletions docs/gitbook/operations/runbooks.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,12 @@ The `panther-aws-remediation` lambda executes automated infrastructure remediati
Failure Impact
* Failure of this lambda will mean specific remediations are failing and infrastructure will remain in violation of policy.

## panther-cfn-custom-resources
Used by CloudFormation when deploying or updating Panther.

Failure Impact
* Panther itself will not be affected, but deployments may be failing

## panther-compliance
This ddb table holds policy violation events for associated resources in the `panther-resources` ddb table.

Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ require (
github.com/alecthomas/jsonschema v0.0.0-20200217214135-7152f22193c9
github.com/aws/aws-lambda-go v1.16.0
github.com/aws/aws-sdk-go v1.30.7
github.com/cenkalti/backoff v2.2.1+incompatible
github.com/cenkalti/backoff/v4 v4.0.2
github.com/go-openapi/errors v0.19.4
github.com/go-openapi/runtime v0.19.15
github.com/go-openapi/strfmt v0.19.5
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ github.com/aws/aws-lambda-go v1.16.0 h1:9+Pp1/6cjEXYhwadp8faFXKSOWt7/tHRCnQxQmKv
github.com/aws/aws-lambda-go v1.16.0/go.mod h1:FEwgPLE6+8wcGBTe5cJN3JWurd1Ztm9zN4jsXsjzKKw=
github.com/aws/aws-sdk-go v1.30.7 h1:IaXfqtioP6p9SFAnNfsqdNczbR5UNbYqvcZUSsCAdTY=
github.com/aws/aws-sdk-go v1.30.7/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4=
github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
github.com/cenkalti/backoff/v4 v4.0.2 h1:JIufpQLbh4DkbQoii76ItQIUFzevQSqOLZca4eamEDs=
github.com/cenkalti/backoff/v4 v4.0.2/go.mod h1:eEew/i+1Q6OrCDZh3WiXYv3+nJwBASZ8Bog/87DQnVg=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import (
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/cloudformation"
"github.com/aws/aws-sdk-go/service/cloudformation/cloudformationiface"
"github.com/cenkalti/backoff"
"github.com/cenkalti/backoff/v4"
"github.com/pkg/errors"
"go.uber.org/zap"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ import (
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/service/iam"
"github.com/aws/aws-sdk-go/service/iam/iamiface"
"github.com/cenkalti/backoff"
"github.com/cenkalti/backoff/v4"
"go.uber.org/zap"

apimodels "github.com/panther-labs/panther/api/gateway/resources/models"
Expand Down
52 changes: 52 additions & 0 deletions internal/core/custom_resources/main/lambda.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package main

/**
* Panther is a Cloud-Native SIEM for the Modern Security Team.
* Copyright (C) 2020 Panther Labs Inc
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

import (
"context"
"fmt"

"github.com/aws/aws-lambda-go/cfn"
"github.com/aws/aws-lambda-go/lambda"
"go.uber.org/zap"

"github.com/panther-labs/panther/internal/core/custom_resources/resources"
"github.com/panther-labs/panther/pkg/lambdalogger"
)

// Returns physicalResourceID and outputs
func customResourceHandler(ctx context.Context, event cfn.Event) (string, map[string]interface{}, error) {
_, logger := lambdalogger.ConfigureGlobal(ctx, map[string]interface{}{
"requestType": event.RequestType,
"resourceType": event.ResourceType,
"physicalResourceId": event.PhysicalResourceID,
})
logger.Info("received custom resource request", zap.Any("event", event))

handler, ok := resources.CustomResources[event.ResourceType]
if !ok {
return "", nil, fmt.Errorf("unsupported resource type: %s", event.ResourceType)
}

return handler(ctx, event)
}

func main() {
lambda.Start(cfn.LambdaWrap(customResourceHandler))
}
Loading

0 comments on commit 21c1623

Please sign in to comment.