Skip to content

When using user password authentication, there is a problem with the usage of 0.12.0. #2713

Description

@become-nice

Environment

os: debian 12
python-etcd3 version: 0.12.0
grpcio version: 1.72.0

bug

When SSL is not enabled on etcd server and user password authentication is used, an error message appears, indicating that a secure channel is not used.

grpc._channel._InactiveRpcError: <_InactiveRpcError of RPC that terminated with:
	status = StatusCode.UNAUTHENTICATED
	details = "Established channel does not have a sufficient security level to transfer call credential."
	debug_error_string = "UNKNOWN:Error received from peer  {grpc_message:"Established channel does not have a sufficient security level to transfer call credential.", grpc_status:16, created_time:"xxxxxx"}"

Reason

Because in the current implementation, call_credentials and insecure_channel are bound together using.
The function of call_credentials is to write metadata, that is, token information, to the rpc request package. However, when calling the PUT/GET interface, call_credentials and metadata are passed in at the same time. Metadata is also token information. These two parameters are repeated. When grpc version > 1.44.0, call_credentials and insecure_channel cannot be used at the same time.

    @_handle_errors
    def put(self, key, value, lease=None, prev_kv=False):
        """
        Save a value to etcd.

        Example usage:

        .. code-block:: python

            >>> import etcd3
            >>> etcd = etcd3.client()
            >>> etcd.put('/thing/key', 'hello world')

        :param key: key in etcd to set
        :param value: value to set key to
        :type value: bytes
        :param lease: Lease to associate with this key.
        :type lease: either :class:`.Lease`, or int (ID of lease)
        :param prev_kv: return the previous key-value pair
        :type prev_kv: bool
        :returns: a response containing a header and the prev_kv
        :rtype: :class:`.rpc_pb2.PutResponse`
        """
        put_request = self._build_put_request(key, value, lease=lease,
                                              prev_kv=prev_kv)
        return self.kvstub.Put(
            put_request,
            self.timeout,
            credentials=self.call_credentials,
            metadata=self.metadata
        )

Solve

When SSL is not enabled, call_credentials can be copied to None, thus avoiding the use of call_credentials while using insecure_channel.

class Etcd3Client(object):
    def __init__(self, host='localhost', port=2379,
                 ca_cert=None, cert_key=None, cert_cert=None, timeout=None,
                 user=None, password=None, grpc_options=None):
          ......
        if all(cred_params):
            self.auth_stub = etcdrpc.AuthStub(self.channel)
            auth_request = etcdrpc.AuthenticateRequest(
                name=user,
                password=password
            )

            resp = self.auth_stub.Authenticate(auth_request, self.timeout)
            self.metadata = (('token', resp.token),)
            if ca_cert is not None:
                self.call_credentials = grpc.metadata_call_credentials(
                    EtcdTokenCallCredentials(resp.token))

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions