skip to Main Content

I am trying to connect to a Windows EC2 instance and run some commands against it using pywinrm.
I am using the following code to create a session:
session = winrm.Session(ec2_instance.public_dns_name, auth=(user_name, password))
which works fine.

Now, when I use the session object created above to run a command like:
session.run_ps("hostname") or session.run_cmd("hostname") -> it fails with a timeout error because the firewall rules for WinRM ports 5985 and 5986 are not configured (The security group on AWS side has the ports open but the VM does not have it).

Once the inbound rule for ports 5985 and 5986 is configured on the EC2 instance, running any command fails with the following error:
Exception has occurred: InvalidCredentialsError the specified credentials were rejected by the server

I know that error message is misleading because the credentials are correct.
The reason I say that the credentials are correct because when I run the following from the EC2 instance:

Set-Item -Force WSMan:localhostServiceauthBasic $true
Set-Item -Force WSMan:localhostServiceAllowUnencrypted $true

And then run the command using my code, it all works fine.

Now, what I am trying to find is, a way to enable the AllowUnencrypted value through my python code.
I have looked at using Kerberos but it seems like I need to create an AWS Managed Microsoft AD directory which will incur cost to my organization.

I have also tried to use NTLM like this:

protocol = Protocol(
            endpoint=f"https://{ec2_instance.public_dns_name}:5985/wsman",
            transport="ntlm",
            username="Administrator",
            password="Password",
            server_cert_validation="ignore",
        )

shell_id = protocol.open_shell()

But I get the following error:

HTTPSConnectionPool(host='ec2-x-x-x-x.us-west-2.compute.amazonaws.com', port=5985): Max retries exceeded with url: /wsman (Caused by SSLError(SSLError(1, '[SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:1129)')))

Any help is appreciated.

Thanks

2

Answers


  1. Chosen as BEST ANSWER

    Here is the solution that worked for me:

    Step 1: Use AWS SSM to run commands on an EC2 instance. These commands will

    • Set WMan attributes Basic Authentication to True and AllowUnencrypted to True.
    • Create Windows Firewall Rules with ports 5985 and 5986.
    Set-Item -Force WSMan:localhostServiceauthBasic $true
    Set-Item -Force WSMan:localhostServiceAllowUnencrypted $true
    New-NetFirewallRule -DisplayName "Allow WinRM Ports" -Direction Inbound -Action Allow -Protocol TCP -LocalPort 5985-5986
    

    I got help from here: How to execute commands on AWS Instance using Boto3

    AMIs with SSM pre-installed: https://docs.aws.amazon.com/systems-manager/latest/userguide/sysman-install-ssm-win.html

    Note: The commands can only be run on an EC2 instance if it has this IAM profile associated to it: ARN = arn:aws:iam::<your_aws_account_id>:instance-profile/AmazonSSMRoleForInstancesQuickSetup Name = AmazonSSMRoleForInstancesQuickSetup This can be done using boto3 EC2 client method associate_iam_instance_profile()

    Once the IAM is associated to the EC2 instance, it takes a minute or two to take this effect and get listed under describe_instance_information() method of boto3 ssm client. Make sure to add a waiting method for your EC2 instance to be listed under the output of the above method before trying to run any command.

    Step 2: Use WinRM python library to bring EBS disk online, initialize, partition and format the disk.

    Note: I could have used SSM to run the commands mentioned above but WinRM provides better output which can be converted to JSON and used for further validation.

    Step 3: Code to decrypt password for login:

    from winrm.protocol import Protocol
    from Crypto.PublicKey import RSA
    from Crypto.Cipher import PKCS1_v1_5
    
    with open(private_key_file_path, "r") as key_file:
         key_text = key_file.read()
            
    
         key = RSA.importKey(key_text)
         cipher = PKCS1_v1_5.new(key)
         password = cipher.decrypt(base64.b64decode(password_data),None).decode("utf-8")
    

  2. "HTTPSConnectionPool(host=’ec2-x-x-x-x.us-west-2.compute.amazonaws.com’, port=5985): Max retries exceeded with url: /wsman (Caused by SSLError(SSLError(1, ‘[SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:1129)’)))"

    From your error, port 5985 is HTTP listener where as HTTPS should be port 5986.

    Change endpoint port to 5986 and give a try "endpoint=f"https://{ec2_instance.public_dns_name}:5986/wsman","

    Sorry I’m unable to add comment yet.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search