Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 2 additions & 1 deletion internal/cmds/cmds.go
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,8 @@ func enable(ctx *log.Context, h types.HandlerEnvironment, report *types.RunComma

blobCreateOrReplaceError := "Error creating AppendBlob '%s' using SAS token or Managed identity. Please use a valid blob SAS URI with [read, append, create, write] permissions OR managed identity. If managed identity is used, make sure Azure blob and identity exist, and identity has been given access to storage blob's container with 'Storage Blob Data Contributor' role assignment. In case of user-assigned identity, make sure you add it under VM's identity and provide outputBlobUri / errorBlobUri and corresponding clientId in outputBlobManagedIdentity / errorBlobManagedIdentity parameter(s). In case of system-assigned identity, do not use outputBlobManagedIdentity / errorBlobManagedIdentity parameter(s). For more info, refer https://aka.ms/RunCommandManagedLinux"

// TO-DO: disable output blob if the policy settings has disableOutputBlobs set to true.
// DisableOutputBlobs (policy settings) should have already been validated in ValidateHandlerSettingsAgainstPolicy,
// so we don't need to check it again. If a blob URI was passed in, we assume disableOutputBlobs == false.
var outputBlobSASRef *storage.Blob
var outputBlobAppendClient *appendblob.Client
var outputBlobAppendCreateOrReplaceError error
Expand Down
47 changes: 43 additions & 4 deletions internal/cmds/cmds_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1516,7 +1516,7 @@ func Test_downloadScript_AllowedByAllowlist(t *testing.T) {
require.NoError(t, err)
}

func setupPolicyE2E(t *testing.T, dataDir, extName string, seqNum int, scriptURI string, treatFailureAsDeploymentFailure bool, policy *extensionpolicysettingsrc.RCv2ExtensionPolicySettings,
func setupPolicyE2E(t *testing.T, dataDir, extName string, seqNum int, scriptURI string, treatFailureAsDeploymentFailure bool, outputBlobURI string, errorBlobURI string, policy *extensionpolicysettingsrc.RCv2ExtensionPolicySettings,
) types.HandlerEnvironment {
t.Helper()
configFolder := create_folder(t, dataDir, "config")
Expand All @@ -1537,6 +1537,8 @@ func setupPolicyE2E(t *testing.T, dataDir, extName string, seqNum int, scriptURI
"scriptUri": scriptURI,
"scriptType": string(handlersettings.DownloadedScript),
},
"OutputBlobURI": outputBlobURI,
"ErrorBlobURI": errorBlobURI,
"treatFailureAsDeploymentFailure": treatFailureAsDeploymentFailure,
},
}
Expand Down Expand Up @@ -1606,7 +1608,7 @@ func Test_enable_e2e_extension_policy_settings_pass(t *testing.T) {
DownloadedScriptsAllowlist: []string{correctHash},
}
// Policy will be marshaled and written to a file in the config folder.
fakeEnv := setupPolicyE2E(t, dataDir, extName, seqNum, srv.URL+"/script.sh", false, policy)
fakeEnv := setupPolicyE2E(t, dataDir, extName, seqNum, srv.URL+"/script.sh", false, "", "", policy)

scriptWasExecuted := false
RunCmd = func(ctx *log.Context, dir, scriptFilePath string, cfg *handlersettings.HandlerSettings, metadata types.RCMetadata) (error, int) {
Expand Down Expand Up @@ -1642,7 +1644,7 @@ func Test_enable_e2e_extension_policy_settings_block_statussuccess(t *testing.T)
DownloadedScriptsAllowlist: []string{"000000000000"},
}
// Policy will be marshaled and written to a file in the config folder.
fakeEnv := setupPolicyE2E(t, dataDir, extName, seqNum, srv.URL+"/script.sh", false, policy)
fakeEnv := setupPolicyE2E(t, dataDir, extName, seqNum, srv.URL+"/script.sh", false, "", "", policy)

scriptWasExecuted := false
RunCmd = func(ctx *log.Context, dir, scriptFilePath string, cfg *handlersettings.HandlerSettings, metadata types.RCMetadata) (error, int) {
Expand Down Expand Up @@ -1678,7 +1680,7 @@ func Test_enable_e2e_extension_policy_settings_block_statusfail(t *testing.T) {
DownloadedScriptsAllowlist: []string{"000000000000"},
}
// treatFailureAsDeploymentFailure set to true
fakeEnv := setupPolicyE2E(t, dataDir, extName, seqNum, srv.URL+"/script.sh", true, policy)
fakeEnv := setupPolicyE2E(t, dataDir, extName, seqNum, srv.URL+"/script.sh", true, "", "", policy)

scriptWasExecuted := false
RunCmd = func(ctx *log.Context, dir, scriptFilePath string, cfg *handlersettings.HandlerSettings, metadata types.RCMetadata) (error, int) {
Expand All @@ -1694,3 +1696,40 @@ func Test_enable_e2e_extension_policy_settings_block_statusfail(t *testing.T) {
require.Equal(t, types.StatusError, report[0].Status.Status, "status report should indicate failure")
require.True(t, strings.Contains(report[0].Status.FormattedMessage.Message, "executionState\":\"Failed\",\"executionMessage\":\"Execution failed"), "execution message should indicate failure")
}

func Test_enable_e2e_extension_policy_settings_block_statussuccess_disableOutputBlobs(t *testing.T) {
ctx := log.NewContext(log.NewNopLogger())
extName, seqNum := "badPolicyRun", 0
scriptContent := []byte("#!/bin/bash\necho hello\n")

srv := make_server_with_content(scriptContent)
defer srv.Close()

dataDir, err := os.MkdirTemp("", "policy-pass")
require.Nil(t, err)
defer os.RemoveAll(dataDir)

policy := &extensionpolicysettingsrc.RCv2ExtensionPolicySettings{
LimitScripts: "alloweddownloaded",
DownloadedScriptsAllowlist: []string{"000000000000"},
DisableOutputBlobs: true,
}
// Policy will be marshaled and written to a file in the config folder.
fakeEnv := setupPolicyE2E(t, dataDir, extName, seqNum, srv.URL+"/script.sh", false, "https://example.com/outputBlob", "", policy)

scriptWasExecuted := false
RunCmd = func(ctx *log.Context, dir, scriptFilePath string, cfg *handlersettings.HandlerSettings, metadata types.RCMetadata) (error, int) {
scriptWasExecuted = true
return nil, 0
}

err = commandProcessor.ProcessHandlerCommandWithDetails(ctx, CmdEnable, fakeEnv, extName, seqNum, constants.DownloadFolder, dataDir)
require.Nil(t, err, "enable command should succeed")
require.False(t, scriptWasExecuted, "script should not be executed because output blobs are disabled")

report := readStatusReport(t, fakeEnv, extName, seqNum) // verify status report exists and is valid
require.Equal(t, types.StatusSuccess, report[0].Status.Status, "status report should indicate success")
require.True(t, strings.Contains(report[0].Status.FormattedMessage.Message, "executionState\":\"Failed\",\"executionMessage\":\"Execution failed"), "execution message should indicate failure")
require.True(t, strings.Contains(report[0].Status.FormattedMessage.Message, "output blobs are disabled in policy, but settings specify"), "execution message should indicate failure")

}
15 changes: 8 additions & 7 deletions internal/constants/exitcodes.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@ const (
ExitCode_Okay = 0

// User errors (-100s):
ExitCode_ScriptBlobDownloadFailed = -100
ExitCode_BlobCreateOrReplaceFailed = -101
ExitCode_RunAsLookupUserFailed = -102
ExitCode_ScriptTypeNotAllowedByExtensionPolicy = -103
ExitCode_CommandIdNotAllowedByExtensionPolicy = -104
ExitCode_RunAsUserNotAllowedByExtensionPolicy = -105
ExitCode_DownloadedScriptBlockedByExtensionPolicy = -106
ExitCode_ScriptBlobDownloadFailed = -100
ExitCode_BlobCreateOrReplaceFailed = -101
ExitCode_RunAsLookupUserFailed = -102
ExitCode_ScriptTypeNotAllowedByExtensionPolicy = -103
ExitCode_CommandIdNotAllowedByExtensionPolicy = -104
ExitCode_RunAsUserNotAllowedByExtensionPolicy = -105
ExitCode_DownloadedScriptBlockedByExtensionPolicy = -106
ExitCode_OutputBlobSpecifiedButNotAllowedByExtensionPolicy = -107

// Service Errors (-200s):
ExitCode_CreateDataDirectoryFailed = -200
Expand Down
22 changes: 21 additions & 1 deletion internal/extensionpolicysettingsrc/extensionpolicysettingsrc.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"github.com/Azure/azure-extension-platform/pkg/extensionpolicysettings"
"github.com/Azure/run-command-handler-linux/internal/constants"
"github.com/Azure/run-command-handler-linux/internal/handlersettings"
"github.com/Azure/run-command-handler-linux/pkg/download"
"github.com/go-kit/kit/log"
"github.com/pkg/errors"
)
Expand Down Expand Up @@ -59,8 +60,13 @@ func ValidateHandlerSettingsAgainstPolicy(ctx *log.Context, settings *handlerset
return err, constants.ExitCode_RunAsUserNotAllowedByExtensionPolicy
}
}
if policy.DisableOutputBlobs {
if err := ValidateDisableOutputBlobs(ctx, settings, policy); err != nil {
return err, constants.ExitCode_OutputBlobSpecifiedButNotAllowedByExtensionPolicy
}
}

// TO-DO: Validate Disable Outputblob and RequireSigning once those features are implemented for RCv2.
// TO-DO: Validate RequireSigning once that feature is implemented for RCv2.

return nil, 0
}
Expand Down Expand Up @@ -104,3 +110,17 @@ func ValidateRunAsUser(ctx *log.Context, settings *handlersettings.HandlerSettin
}
return nil
}

func ValidateDisableOutputBlobs(ctx *log.Context, settings *handlersettings.HandlerSettings, policy *RCv2ExtensionPolicySettings) error {
if policy.DisableOutputBlobs {
trimmedOutputBlobURI := strings.TrimSpace(settings.OutputBlobURI)
trimmedErrorBlobURI := strings.TrimSpace(settings.ErrorBlobURI)

if trimmedOutputBlobURI != "" || trimmedErrorBlobURI != "" {
err := fmt.Errorf("output blobs are disabled in policy, but settings specify outputBlobURI '%s' or errorBlobURI '%s'", download.GetUriForLogging(settings.OutputBlobURI), download.GetUriForLogging(settings.ErrorBlobURI))
ctx.Log("message", "output blobs are disabled in policy, but settings specify output or error blob URIs", "error", err, "outputBlobURI", download.GetUriForLogging(settings.OutputBlobURI), "errorBlobURI", download.GetUriForLogging(settings.ErrorBlobURI))
return err
Comment thread
alsanmsft marked this conversation as resolved.
}
}
return nil
}
Loading
Loading