Skip to content

Commit

Permalink
Add TLS support for Mattermost in Botkube
Browse files Browse the repository at this point in the history
Closes #81
  • Loading branch information
mugdha-adhav committed May 1, 2019
1 parent 06e1b3c commit f2048fb
Show file tree
Hide file tree
Showing 6 changed files with 305 additions and 17 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ $ kubectl create ns botkube && kubectl create -f deploy-all-in-one.yaml -n botku

- Check pod status in botkube namespace. Once running, send **@BotKube ping** in the Slack channel to confirm if BotKube is responding correctly.

- To deploy with TLS, download and use deploy-all-in-one-tls.yaml. Replace **ENCODED_CERTIFICATE** with your base64 encoded certificate value in the secret.

## Add BotKube to your Mattermost team
Before adding `BotKube` to your Mattermost team, please make sure you have all the pre-requisites working.

Expand All @@ -92,6 +94,7 @@ Before adding `BotKube` to your Mattermost team, please make sure you have all t
In the helm chart, config.yaml or deploy-all-in-one.yaml update the following fields for enabling Mattermost support and providing Mattermost config parameters.

**MATTERMOST_SERVER_URL** is the URL where Mattermost is running<br>
**MATTERMOST_CERT** is the SSL certificate file for HTTPS connection. Place it in Helm directory and specify the path<br>
**MATTERMOST_TOKEN** is the Token you received after installing BotKube user and creating Personal Access Token<br>
**MATTERMOST_TEAM** is the team name where BotKube will be added<br>
**MATTERMOST_CHANNEL** is the channel name where BotKube will be added<br>
Expand All @@ -102,6 +105,7 @@ In the helm chart, config.yaml or deploy-all-in-one.yaml update the following fi
$ helm install --name botkube --namespace botkube \
--set config.communications.mattermost.enabled=true \
--set config.communications.mattermost.url={MATTERMOST_SERVER_URL} \
--set config.communications.mattermost.cert={MATTERMOST_CERT} \
--set config.communications.mattermost.token={MATTERMOST_TOKEN} \
--set config.communications.mattermost.team={MATTERMOST_TEAM} \
--set config.communications.mattermost.channel={MATTERMOST_CHANNEL} \
Expand Down
253 changes: 253 additions & 0 deletions deploy-all-in-one-tls.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,253 @@
---
# Configmap
apiVersion: v1
kind: ConfigMap
metadata:
name: botkube-configmap
labels:
app: botkube
data:
config.yaml: |
## Resources you want to watch
resources:
- name: pods # Name of the resources e.g pods, deployments, ingresses, etc. (Resource name must be in plural form)
namespaces: # List of namespaces, "all" will watch all the namespaces
- all
events: # List of lifecycle events you want to receive, e.g create, update, delete OR all
- create
- delete
- name: services
namespaces:
- all
events:
- create
- delete
- name: deployments
namespaces:
- all
events:
- create
- delete
- name: ingresses
namespaces:
- all
events:
- create
- delete
- name: nodes
namespaces:
- all
events:
- create
- delete
- name: namespaces
namespaces:
- all
events:
- create
- delete
- name: persistentvolumes
namespaces:
- all
events:
- create
- delete
- name: persistentvolumeclaims
namespaces:
- all
events:
- create
- delete
- name: secrets
namespaces:
- all
events:
- create
- delete
- name: configmaps
namespaces:
- all
events:
- create
- delete
- name: daemonsets
namespaces:
- all
events:
- create
- delete
- name: jobs
namespaces:
- all
events:
- create
- delete
- name: roles
namespaces:
- all
events:
- create
- delete
- name: rolebindings
namespaces:
- all
events:
- create
- delete
- name: clusterroles
namespaces:
- all
events:
- create
- delete
- name: clusterrolebindings
namespace:
- all
events:
- create
- delete
- name: nodes
namespaces:
- all
events:
- create
- delete
# K8S error/warning events you want to receive for the configured resources
events:
types:
#- normal
- warning
# Check true if you want to receive recommendations
# about the best practices for the created resource
recommendations: true
# Channels configuration
communications:
# Settings for Slack
slack:
enabled: false
channel: 'SLACK_CHANNEL'
token: 'SLACK_API_TOKEN'
# Settings for Mattermost
mattermost:
enabled: false
url: 'MATTERMOST_SERVER_URL' # URL where Mattermost is running. e.g https://example.com:9243
token: 'MATTERMOST_TOKEN' # Personal Access token generated by BotKube user
team: 'MATTERMOST_TEAM' # Mattermost Team to configure with BotKube
channel: 'MATTERMOST_CHANNEL' # Mattermost Channel for receiving BotKube alerts
# Settings for ELS
elasticsearch:
enable: false
server: 'ELASTICSEARCH_ADDRESS' # e.g https://example.com:9243
username: 'ELASTICSEARCH_USERNAME'
password: 'ELASTICSEARCH_PASSWORD'
# ELS index settings
index:
name: botkube
type: botkube-event
shards: 1
replicas: 0
# Setting to support multiple clusters
settings:
# Cluster name to differentiate incoming messages
clustername: not-configured
# Set false to disable kubectl commands execution
allowkubectl: false
---
# serviceaccount
apiVersion: v1
kind: ServiceAccount
metadata:
name: botkube-sa
labels:
app: botkube
---
# Source: botkube/templates/clusterrole.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: botkube-clusterrole
labels:
app: botkube
rules:
- apiGroups: ["*"]
resources: ["*"]
verbs: ["get", "watch", "list"]
---
# clusterrolebinding
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: botkube-clusterrolebinding
labels:
app: botkube
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: botkube-clusterrole
subjects:
- kind: ServiceAccount
name: botkube-sa
namespace: botkube
---
# Secret
apiVersion: v1
kind: Secret
metadata:
name: botkube-secret
labels:
app: botkube
data:
ca-certificates.crt: ENCODED_CERTIFICATE
---
# deployment
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: botkube
labels:
component: controller
app: botkube
spec:
replicas: 1
selector:
matchLabels:
component: controller
app: botkube
template:
metadata:
labels:
component: controller
app: botkube
spec:
serviceAccountName: botkube-sa
containers:
- name: botkube
image: "infracloud/botkube:0.7.0"
imagePullPolicy: Always
volumeMounts:
- name: config-volume
mountPath: "/config"
- name: certs
mountPath: "/etc/ssl/certs"
env:
- name: CONFIG_PATH
value: "/config/"
# set one of the log levels- info, warn, debug, error, fatal, panic
- name: LOG_LEVEL
value: "info"
# set BotKube release version
- name: BOTKUBE_VERSION
value: 0.7.0
volumes:
- name: config-volume
configMap:
name: botkube-configmap
- name: certs
secret:
secretName: botkube-secret
9 changes: 9 additions & 0 deletions helm/botkube/templates/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ spec:
volumeMounts:
- name: config-volume
mountPath: "/config"
{{- if ne .Values.config.communications.mattermost.cert "None" }}
- name: certs
mountPath: "/etc/ssl/certs"
{{ end }}
env:
- name: CONFIG_PATH
value: "/config/"
Expand All @@ -42,3 +46,8 @@ spec:
- name: config-volume
configMap:
name: {{ include "botkube.fullname" . }}-configmap
{{- if ne .Values.config.communications.mattermost.cert "None" }}
- name: certs
secret:
secretName: {{ include "botkube.fullname" . }}-secret
{{ end }}
15 changes: 15 additions & 0 deletions helm/botkube/templates/secret.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{{- if ne .Values.config.communications.mattermost.cert "None" }}

apiVersion: v1
kind: Secret
metadata:
name: {{ include "botkube.fullname" . }}-secret
labels:
app.kubernetes.io/name: {{ include "botkube.name" . }}
helm.sh/chart: {{ include "botkube.chart" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
data:
ca-certificates.crt: {{ .Files.Get (printf "%s" .Values.config.communications.mattermost.cert) | b64enc }}

{{ end }}
1 change: 1 addition & 0 deletions helm/botkube/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ config:
mattermost:
enabled: false
url: 'MATTERMOST_SERVER_URL' # URL where Mattermost is running. e.g https://example.com:9243
cert: None # SSL Certificate file. Leave it None for http connection. e.g certs/my-cert.crt
token: 'MATTERMOST_TOKEN' # Personal Access token generated by BotKube user
team: 'MATTERMOST_TEAM' # Mattermost Team to configure with BotKube
channel: 'MATTERMOST_CHANNEL' # Mattermost Channel for receiving BotKube alerts
Expand Down
40 changes: 23 additions & 17 deletions pkg/mattermost/mattermost.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package mattermost

import (
"fmt"
"net/url"
"strings"

"github.com/infracloudio/botkube/pkg/config"
Expand All @@ -15,10 +16,10 @@ var client *model.Client4
const (
// BotName stores Botkube details
BotName = "botkube"
// ChannelPurpose describes the purpose of Botkube channel
ChannelPurpose = "Botkube alerts"
// WebSocketProtocol stores protocol initials for web socket
WebSocketProtocol = "ws:"
WebSocketProtocol = "ws://"
// WebSocketSecureProtocol stores protocol initials for web socket
WebSocketSecureProtocol = "wss://"
)

// Bot listens for user's message, execute commands and sends back the response
Expand Down Expand Up @@ -56,32 +57,37 @@ func NewMattermostBot() *Bot {
}
}

// Channel structure in Mattermost
func mmChannel(channelName, teamID string) *model.Channel {
return &model.Channel{
Name: channelName,
DisplayName: channelName,
Purpose: ChannelPurpose,
Type: model.CHANNEL_OPEN,
TeamId: teamID,
}
}

// Start establishes mattermost connection and listens for messages
func (b *Bot) Start() {
client = model.NewAPIv4Client(b.ServerURL)
client.SetOAuthToken(b.Token)

// Check if Mattermost URL is valid
checkURL, err := url.Parse(b.ServerURL)
if err != nil {
logging.Logger.Error("The Mattermost URL entered is incorrect. URL: ", b.ServerURL, "\nError: ", err)
return
}

// Check connection to Mattermost server
err := checkServerConnection()
err = checkServerConnection()
if err != nil {
logging.Logger.Error("There was a problem pinging the Mattermost server URL: ", b.ServerURL, "\nError: ", err)
return
}

// Create WebSocketClient and handle messages
webSocketURL := WebSocketProtocol + strings.SplitN(b.ServerURL, ":", 2)[1]
webSocketClient, _ := model.NewWebSocketClient4(webSocketURL, client.AuthToken)
webSocketURL := WebSocketProtocol + checkURL.Host
if checkURL.Scheme == "https" {
webSocketURL = WebSocketSecureProtocol + checkURL.Host
}
var modelError *model.AppError
webSocketClient, modelError := model.NewWebSocketClient4(webSocketURL, client.AuthToken)
if modelError != nil {
logging.Logger.Error("Error creating WebSocket for Mattermost connectivity. \nError: ", modelError)
return
}

webSocketClient.Listen()
go func() {
for {
Expand Down

0 comments on commit f2048fb

Please sign in to comment.