The "Origin Custom Headers" you're configuring aren't headers which get added to the response from the origin, but rather to the request made to the origin. From the CloudFront documentation:
You can configure CloudFront to add custom headers to the requests
that it sends to your origin. These custom headers enable you to send
and gather information from your origin that you don’t get with
typical viewer requests. These headers can even be customized for each
origin. CloudFront supports custom headers for both for custom and
Amazon S3 origins.
So that's no option for adding response headers. While there exists the possibility to use S3 metadata to influence the headers returned to the viewer, this only works for the Content-Type
-header, so this is neither an option.
The best option is to use a Lambda@Edge function. While that sounds like a cumbersome and expensive solution, it actually isn't. For your use case the code of that Lambda@Edge function could be as simple as shown below:
def lambda_handler(event, context):
response = event["Records"][0]["cf"]["response"]
response["headers"]["x-frame-options"] = ":sameorigin"
return response
When you configure this Lambda@Edge function to trigger on "Origin Response" events in CloudFront, it won't be executed for every viewer request, but instead only when the content returned to the viewer isn't cached by CloudFront and has to be fetched from S3 first. This helps minimizing the additionally latency and cost induced by the execution of the Lambda@Edge function.