Keeper-Security / Commander

Keeper Commander is a python-based CLI and SDK interface to the Keeper Security platform. Provides administrative controls, reporting, import/export and vault management.
https://www.keepersecurity.com/commander.html
MIT License
184 stars 74 forks source link

Use Commander modules in Python script #1154

Closed ChristofferLB closed 9 months ago

ChristofferLB commented 9 months ago

Hi,

I have a use case where I want to have an automation runbook in Azure creating and sharing records in Keeper. I've tried to integrate with the Keeper Commander modules but keep getting stuck in the login phase, it keeps prompting me for Device Approval in my runbook.

We have a container setup for Device Approval, which works fine. This account is a local account within Keeper and I can login in the web browser (incognito) and using Keeper Commander locally using a master password without getting this Device Approval. When I run the code in my runbook it does prompt me for approval for some reason.

The login code looks like this.

from keepercommander.params import KeeperParams
from keepercommander.commands.recordv3 import RecordAddCommand
from keepercommander.commands.register import OneTimeShareCreateCommand
from keepercommander import api

def login_keeper():

    try:
        # Create params file
        params = KeeperParams()

        #params = get_params_from_config("config.json")

        # Get credentials for Keeper from Automation account credentials
        keeper_cred = get_credential("Keeper_Secret")

        # Get Keeper login
        keeper_user = keeper_cred[0]
        keeper_password = keeper_cred[1]

        params.user = keeper_user
        params.password = keeper_password

        # Sign in to Keeper
        api.login(params)
        api.sync_down(params)
    except Exception as e:
        print(f"Error signing into Keeper: {e}")
        raise

I've tried both with generating params with the class and using a file and also hard-coding the credentials, same result. The code runs fine locally in VS Code and I'm able to sign in without getting prompted for Device Approval. I can see the successful sign in in the "Recent Activity" in the admin console.

The code that generates the approval prompt is most likely:

loginv3.py

LoginV3Flow.verifyDevice

Can you share some insight why I get this in the runbook and how I can fix it?

Thanks a lot!

sk-keeper commented 9 months ago

Hi, The Commander uses configuration file to keep instance/device context. The default location for this file is $HOME/.keeper/config.json. If this file is not found or corrupted the Commander creates a new one and the backend starts the full login flow. It includes

It is essential that the Commander running in unattended mode preserves device configuration stored in the config.json file. Please

  1. make sure that the config.json file is properly configured (device is approved and 2fa is not asked)
  2. Transfer this file to Azure. Azure's Functions support local file storage
  3. Uncomment the following line in your example
    params = get_params_from_config("config.json")

params = KeeperParams() creates a new configuration file that triggers the full login flow.

ChristofferLB commented 9 months ago

Hi,

Thanks for the info.

I managed, with your input, to get it working.

Since an Azure runbook doesn't support persistent files I'm adding the necessary file everytime the script runs into a temp directory. Not the best solution, but we need to use a runbook for now.

I first signed in to Keeper using the browser in order to get the necessary config.json data that has gotten a device approval already. This data is then added into the variable "config_file" and then written to disk.

from keepercommander.__main__ import get_params_from_config
config_file = """{
"user": "removed",
"server": "removed",
"clone_code": "removed",
"device_token": "removed",
"private_key": "removed"
}"""

f = open(r"C:\Users\ContainerUser\AppData\Local\Temp\config.json", "w+")
f.write(config_file)
f.close()

params = get_params_from_config(r"C:\Users\ContainerUser\AppData\Local\Temp\config.json")
aaunario-keeper commented 9 months ago

Hi,

Just a security-related suggestion: In lieu of hard-coding your credentials in the script (which would pose a security-risk if you're using a centralized versioning system like Github that others can view), you might want to take advantage of Azure's credential assets, whose values can be retrieved from w/in your script, as documented here: https://learn.microsoft.com/en-us/azure/automation/shared-resources/credentials?tabs=azure-powershell

In addition, you also have the option (though a possibly less secure one) to store those credential values as input parameters for your Runbook instance and retrieve them in your script, as shown here: https://learn.microsoft.com/en-us/azure/automation/runbook-input-parameters.

On Wed, Dec 20, 2023 at 12:40 AM ChristofferLB @.***> wrote:

Hi,

Thanks for the info.

I managed, with your input, to get it working.

Since an Azure runbook doesn't support persistent files I'm adding the necessary file everytime the script runs into a temp directory. Not the best solution, but we need to use a runbook for now.

I first signed in to Keeper using the browser in order to get the necessary config.json data that has gotten a device approval already. This data is then added into the variable "config_file" and then written to disk.

from keepercommander.main import get_params_from_config config_file = """{ "user": "removed", "server": "removed", "clone_code": "removed", "device_token": "removed", "private_key": "removed" }"""

f = open(r"C:\Users\ContainerUser\AppData\Local\Temp\config.json", "w+") f.write(config_file) f.close()

params = get_params_from_config(r"C:\Users\ContainerUser\AppData\Local\Temp\config.json")

— Reply to this email directly, view it on GitHub https://github.com/Keeper-Security/Commander/issues/1154#issuecomment-1863932790, or unsubscribe https://github.com/notifications/unsubscribe-auth/AZDPG4NNE3YDSN4NOIE27TTYKKB4NAVCNFSM6AAAAABAU4CYPKVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTQNRTHEZTENZZGA . You are receiving this because you are subscribed to this thread.Message ID: @.***>

--

Ayrris Aunario | Senior Software Engineer

Mobile 773.986.1194

This email is confidential and is intended for the recipient(s) addressed herein

ChristofferLB commented 9 months ago

Hi again,

Thanks for the suggestion.

I'm was not planning to hardcode any of the sensitive strings, but rather fetch them during runtime using the built-in automation credentials feature.

Just out of curiosity - Which of the strings in the config file would you say is worth fetching instead of hardcoding in the code?

aaunario-keeper commented 9 months ago

Hi Christoffer,

I would say the following config fields are probably the most sensitive (note - your usage of these fields may vary depending on how you choose to do login authentication) : 1) "device_token" 2) "private_key" 3) "clone_code" 3) "user" 4) "password"

On Tue, Jan 2, 2024 at 8:49 AM ChristofferLB @.***> wrote:

Hi again,

Thanks for the suggestion.

I'm was not planning to hardcode any of the sensitive strings, but rather fetch them during runtime using the built-in automation credentials feature.

Just out of curiosity - Which of the strings in the config file would you say is worth fetching instead of hardcoding in the code?

— Reply to this email directly, view it on GitHub https://github.com/Keeper-Security/Commander/issues/1154#issuecomment-1874120476, or unsubscribe https://github.com/notifications/unsubscribe-auth/AZDPG4LDYSYHHHNWHVFJU23YMQM7NAVCNFSM6AAAAABAU4CYPKVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTQNZUGEZDANBXGY . You are receiving this because you commented.Message ID: @.***>

--

Ayrris Aunario | Senior Software Engineer

Mobile 773.986.1194

This email is confidential and is intended for the recipient(s) addressed herein