diff --git a/lower-constraints.txt b/lower-constraints.txt
index 6cb1b44fc0..db92fef36b 100644
--- a/lower-constraints.txt
+++ b/lower-constraints.txt
@@ -50,7 +50,7 @@ msgpack-python==0.4.0
 munch==2.1.0
 netaddr==0.7.18
 netifaces==0.10.4
-openstacksdk==0.11.2
+openstacksdk==0.17.0
 os-client-config==1.28.0
 os-service-types==1.2.0
 os-testr==1.0.0
diff --git a/openstackclient/image/v2/image.py b/openstackclient/image/v2/image.py
index 3d9c199d18..1e67692a54 100644
--- a/openstackclient/image/v2/image.py
+++ b/openstackclient/image/v2/image.py
@@ -16,9 +16,11 @@
 """Image V2 Action Implementations"""
 
 import argparse
+from base64 import b64encode
 import logging
 
 from glanceclient.common import utils as gc_utils
+from openstack.image import image_signer
 from osc_lib.cli import parseractions
 from osc_lib.command import command
 from osc_lib import exceptions
@@ -183,6 +185,22 @@ class CreateImage(command.ShowOne):
             help=_("Force image creation if volume is in use "
                    "(only meaningful with --volume)"),
         )
+        parser.add_argument(
+            '--sign-key-path',
+            metavar="<sign-key-path>",
+            default=[],
+            help=_("Sign the image using the specified private key. "
+                   "Only use in combination with --sign-cert-id")
+        )
+        parser.add_argument(
+            '--sign-cert-id',
+            metavar="<sign-cert-id>",
+            default=[],
+            help=_("The specified certificate UUID is a reference to "
+                   "the certificate in the key manager that corresponds "
+                   "to the public key and is used for signature validation. "
+                   "Only use in combination with --sign-key-path")
+        )
         protected_group = parser.add_mutually_exclusive_group()
         protected_group.add_argument(
             "--protected",
@@ -335,6 +353,46 @@ class CreateImage(command.ShowOne):
                 parsed_args.project_domain,
             ).id
 
+        # sign an image using a given local private key file
+        if parsed_args.sign_key_path or parsed_args.sign_cert_id:
+            if not parsed_args.file:
+                msg = (_("signing an image requires the --file option, "
+                         "passing files via stdin when signing is not "
+                         "supported."))
+                raise exceptions.CommandError(msg)
+            if (len(parsed_args.sign_key_path) < 1 or
+                    len(parsed_args.sign_cert_id) < 1):
+                msg = (_("'sign-key-path' and 'sign-cert-id' must both be "
+                         "specified when attempting to sign an image."))
+                raise exceptions.CommandError(msg)
+            else:
+                sign_key_path = parsed_args.sign_key_path
+                sign_cert_id = parsed_args.sign_cert_id
+                signer = image_signer.ImageSigner()
+                try:
+                    pw = utils.get_password(
+                        self.app.stdin,
+                        prompt=("Please enter private key password, leave "
+                                "empty if none: "),
+                        confirm=False)
+                    if not pw or len(pw) < 1:
+                        pw = None
+                    signer.load_private_key(
+                        sign_key_path,
+                        password=pw)
+                except Exception:
+                    msg = (_("Error during sign operation: private key could "
+                             "not be loaded."))
+                    raise exceptions.CommandError(msg)
+
+                signature = signer.generate_signature(fp)
+                signature_b64 = b64encode(signature)
+                kwargs['img_signature'] = signature_b64
+                kwargs['img_signature_certificate_uuid'] = sign_cert_id
+                kwargs['img_signature_hash_method'] = signer.hash_method
+                if signer.padding_method:
+                    kwargs['img_signature_key_type'] = signer.padding_method
+
         # If a volume is specified.
         if parsed_args.volume:
             volume_client = self.app.client_manager.volume
diff --git a/releasenotes/notes/osc-included-image-signing-a7021a4dbdcf6336.yaml b/releasenotes/notes/osc-included-image-signing-a7021a4dbdcf6336.yaml
new file mode 100644
index 0000000000..7c7a2d6163
--- /dev/null
+++ b/releasenotes/notes/osc-included-image-signing-a7021a4dbdcf6336.yaml
@@ -0,0 +1,11 @@
+---
+features:
+  - |
+    Add options ``--sign-key-path`` and ``--sign-cert-id`` to the ``image create``
+    command.  Tthe image must be present on disk, therefore the ``file`` option
+    is required:
+
+    ``image create --file <filename> --sign-key-path <key-path> --sign-cert-id <secret-id>``.
+
+    A prompt for a password ensures, that the private key can be protected too.
+    [Bug `2002128 <https://storyboard.openstack.org/#!/story/2002128>`_]
\ No newline at end of file
diff --git a/requirements.txt b/requirements.txt
index 2ee03a5cd3..205d4e64ec 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -7,7 +7,7 @@ six>=1.10.0 # MIT
 Babel!=2.4.0,>=2.3.4 # BSD
 cliff!=2.9.0,>=2.8.0 # Apache-2.0
 keystoneauth1>=3.4.0 # Apache-2.0
-openstacksdk>=0.11.2 # Apache-2.0
+openstacksdk>=0.17.0 # Apache-2.0
 osc-lib>=1.10.0 # Apache-2.0
 oslo.i18n>=3.15.3 # Apache-2.0
 oslo.utils>=3.33.0 # Apache-2.0