agent/appconfig/constants_unix.go (128 lines of code) (raw):
// Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License"). You may not
// use this file except in compliance with the License. A copy of the
// License is located at
//
// http://aws.amazon.com/apache2.0/
//
// or in the "license" file accompanying this file. This file 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.
//go:build freebsd || linux || netbsd || openbsd
// +build freebsd linux netbsd openbsd
// Package appconfig manages the configuration of the agent.
package appconfig
import (
"fmt"
"os"
"path/filepath"
"syscall"
"github.com/aws/amazon-ssm-agent/agent/network/certreader"
)
var (
// AgentExtensions specified the root folder for various kinds of downloaded content
AgentData = "/var/lib/amazon/ssm/"
// PackageRoot specifies the directory under which packages will be downloaded and installed
PackageRoot = AgentData + "packages"
// PackageLockRoot specifies the directory under which package lock files will reside
PackageLockRoot = AgentData + "locks/packages"
// PackagePlatform is the platform name to use when looking for packages
PackagePlatform = "linux"
// DaemonRoot specifies the directory where daemon registration information is stored
DaemonRoot = AgentData + "daemons"
// LocalCommandRoot specifies the directory where users can submit command documents offline
LocalCommandRoot = AgentData + "localcommands"
// LocalCommandRootSubmitted is the directory where locally submitted command documents
// are moved when they have been picked up
LocalCommandRootSubmitted = AgentData + "localcommands/submitted"
LocalCommandRootCompleted = AgentData + "localcommands/completed"
// LocalCommandRootInvalid is the directory where locally submitted command documents
// are moved if the service cannot validate the document (generally impossible via cli)
LocalCommandRootInvalid = AgentData + "localcommands/invalid"
// DownloadRoot specifies the directory under which files will be downloaded
DownloadRoot = AgentData + "download/"
// DefaultDataStorePath represents the directory for storing system data
DefaultDataStorePath = AgentData
// EC2ConfigDataStorePath represents the directory for storing ec2 config data
EC2ConfigDataStorePath = "/var/lib/amazon/ec2config/"
// EC2ConfigSettingPath represents the directory for storing ec2 config settings
EC2ConfigSettingPath = "/var/lib/amazon/ec2configservice/"
// UpdaterArtifactsRoot represents the directory for storing update related information
UpdaterArtifactsRoot = AgentData + "update/"
// UpdaterPidLockfile represents the location of the updater lockfile
UpdaterPidLockfile = AgentData + "update.lock"
// DefaultPluginPath represents the directory for storing plugins in SSM
DefaultPluginPath = AgentData + "plugins"
// ManifestCacheDirectory represents the directory for storing all downloaded manifest files
ManifestCacheDirectory = AgentData + "manifests"
// List all plugin names, unfortunately golang doesn't support const arrays of strings
// RebootExitCode that would trigger a Soft Reboot
RebootExitCode = 194
// Default Custom Inventory Inventory Folder
DefaultCustomInventoryFolder = AgentData + "inventory/custom"
// Default Session files Folder
SessionFilesPath = AgentData + "session"
// PowerShellPluginCommandArgs is the arguments of powershell.exe to be used by the runPowerShellScript plugin
PowerShellPluginCommandArgs = "-f"
// Exit Code for a command that exits before completion (generally due to timeout or cancel)
CommandStoppedPreemptivelyExitCode = 137 // Fatal error (128) + signal for SIGKILL (9) = 137
// RunCommandScriptName is the script name where all downloaded or provided commands will be stored
RunCommandScriptName = "_script.sh"
NecessaryAgentBinaryPermissionMask os.FileMode = 0511 // Require read/execute for root, execute for all
DisallowedAgentBinaryPermissionMask os.FileMode = 0022 // Disallow write for group and user
// customCertificateFileName is the name of the custom certificate
customCertificateFileName = "amazon-ssm-agent.crt"
// SSM Agent Update download legacy path
LegacyUpdateDownloadFolder = "/var/log/amazon/ssm/download"
// DefaultEC2SharedCredentialsFilePath represents the filepath for storing credentials for ec2 identity
DefaultEC2SharedCredentialsFilePath = DefaultDataStorePath + "credentials"
)
// PowerShellPluginCommandName is the path of the powershell.exe to be used by the runPowerShellScript plugin
var PowerShellPluginCommandName string
// DefaultProgramFolder is the default folder for SSM
var DefaultProgramFolder = "/etc/amazon/ssm/"
var defaultWorkerPath = "/usr/bin/"
var DefaultSSMAgentBinaryPath = defaultWorkerPath + "amazon-ssm-agent"
var DefaultSSMAgentWorker = defaultWorkerPath + "ssm-agent-worker"
var DefaultDocumentWorker = defaultWorkerPath + "ssm-document-worker"
var DefaultSessionWorker = defaultWorkerPath + "ssm-session-worker"
var DefaultSessionLogger = defaultWorkerPath + "ssm-session-logger"
// AppConfigPath is the path of the AppConfig
var AppConfigPath = DefaultProgramFolder + AppConfigFileName
// CustomCertificatePath is the path of the custom certificate
var CustomCertificatePath = ""
// SeelogFilePath specifies the path to the seelog
var SeelogFilePath = DefaultProgramFolder + SeelogConfigFileName
var RuntimeConfigFolderPath = AgentData + "runtimeconfig"
func init() {
/*
Powershell command used to be powershell in alpha versions, now it's pwsh in prod versions
*/
PowerShellPluginCommandName = "/usr/bin/powershell"
if _, err := os.Stat(PowerShellPluginCommandName); err != nil {
PowerShellPluginCommandName = "/usr/bin/pwsh"
}
// curdir is amazon-ssm-agent current directory path
curdir, err := filepath.Abs(filepath.Dir(os.Args[0]))
if err != nil {
return
}
// if curdir is not default worker dir, update paths of other binaries
if curdir != defaultWorkerPath[:len(defaultWorkerPath)-1] {
if validateAgentBinary("ssm-session-worker", curdir) &&
validateAgentBinary("ssm-agent-worker", curdir) {
DefaultSessionWorker = filepath.Join(curdir, "ssm-session-worker")
DefaultSSMAgentWorker = filepath.Join(curdir, "ssm-agent-worker")
DefaultProgramFolder = curdir
if validateAgentBinary("ssm-document-worker", curdir) {
DefaultDocumentWorker = filepath.Join(curdir, "ssm-document-worker")
}
if validateAgentBinary("ssm-session-logger", curdir) {
DefaultSessionLogger = filepath.Join(curdir, "ssm-session-logger")
}
// Check if config is available in relative path
const relativeConfigFolder = "configuration"
if validateRelativeConfigFile(filepath.Join(curdir, relativeConfigFolder, AppConfigFileName)) {
AppConfigPath = filepath.Join(curdir, relativeConfigFolder, AppConfigFileName)
}
// Check if seelog.xml is available in relative path
if validateRelativeConfigFile(filepath.Join(curdir, relativeConfigFolder, SeelogConfigFileName)) {
SeelogFilePath = filepath.Join(curdir, relativeConfigFolder, SeelogConfigFileName)
}
// Check if certificate is available in relative path
const relativeCertsFolder = "certs"
if _, err := certreader.ReadCertificate(filepath.Join(curdir, relativeCertsFolder, customCertificateFileName)); err == nil {
CustomCertificatePath = filepath.Join(curdir, relativeCertsFolder, customCertificateFileName)
}
}
}
}
func validateAgentBinary(filename, curdir string) bool {
// binaries exist in the directory
if info, err := os.Stat(filepath.Join(curdir, filename)); err == nil {
mode := info.Mode()
fileSys := info.Sys()
if (mode.Perm() & NecessaryAgentBinaryPermissionMask) != NecessaryAgentBinaryPermissionMask {
// Some necessary permissions are not set
fmt.Println("Warning: Some necessary permissions are not set for: ", filename)
return false
}
if (mode.Perm() & DisallowedAgentBinaryPermissionMask) != 0 {
// Some disallowed permissions are set
fmt.Println("Warning: Some disallowed permissions are set for: ", filename)
return false
}
//binary ownership is root
if fileSys.(*syscall.Stat_t).Uid == 0 &&
fileSys.(*syscall.Stat_t).Gid == 0 {
return true
}
}
return false
}
func validateRelativeConfigFile(filePath string) bool {
// Get folder info
info, err := os.Stat(filepath.Dir(filePath))
if err != nil {
return false
}
// Get folder resource information
folderSys := info.Sys()
if folderSys.(*syscall.Stat_t).Uid != 0 ||
folderSys.(*syscall.Stat_t).Gid != 0 {
return false
}
// Get file info
info, err = os.Stat(filePath)
if err != nil {
return false
}
// Check if is file
if !info.Mode().IsRegular() {
return false
}
// check if file is owned by root
fileSys := info.Sys()
if fileSys.(*syscall.Stat_t).Uid != 0 ||
fileSys.(*syscall.Stat_t).Gid != 0 {
return false
}
return true
}