PostgreSQL在SSL模式下返回”服务器不支持SSL,但需要SSL”的错误信息。

huangapple go评论103阅读模式
英文:

PostgreSQL in SSL mode returns 'server does not support SSL, but SSL was required'

问题

你好 PostgreSQL在SSL模式下返回”服务器不支持SSL,但需要SSL”的错误信息。 希望你一切都好!

我正在尝试在一个Postgres Docker容器和一个FastAPI容器之间启用SSL通信,但正如你从标题中可以看出,有些东西不起作用 :/

我阅读了文档,据说我已经按照要求设置了一切。例如:

  1. 我创建了根CA,然后使用根CA为Postgres服务器创建了密钥和签名证书。

  2. 我已经按照以下方式配置了postgresql.conf文件:

... 默认配置

# - SSL -

ssl = on
ssl_ca_file = '/var/lib/postgresql/data/root.crt'
ssl_cert_file = '/var/lib/postgresql/data/server.crt'
ssl_key_file = '/var/lib/postgresql/data/server.key'
#ssl_crl_file = ''
#ssl_crl_dir = ''
#ssl_ciphers = 'HIGH:MEDIUM:+3DES:!aNULL' # allowed SSL ciphers
#ssl_prefer_server_ciphers = on
#ssl_ecdh_curve = 'prime256v1'
#ssl_min_protocol_version = 'TLSv1.2'
#ssl_max_protocol_version = ''
#ssl_dh_params_file = ''
#ssl_passphrase_command = ''
#ssl_passphrase_command_supports_reload = off

... 默认配置

这是我的目录结构:

.
├── docker-compose.yaml
├── Dockerfile
├── main.py
├── postgresql.conf
├── README.md
├── ssl-client
│   ├── root.crt
│   ├── root.csr
│   ├── root.key
│   ├── server.crt
│   ├── server.csr
│   └── server.key
└── ssl-server
    ├── pgdata  [error opening dir]   -> 因为它使用了自己的用户(999)
    ├── root.crt
    ├── root.csr
    ├── root.key
    ├── server.crt
    ├── server.csr
    └── server.key

这是我如何将所有内容传递给容器的方式:

version: '3.8'
services:
  app:
    container_name: python-app
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - '8000:80'
    depends_on:
      - postgres
    networks:
      - postgres-ssl

  postgres:
    container_name: postgres
    image: postgres:latest
    environment:
      POSTGRES_USER: username
      POSTGRES_PASSWORD: password
      POSTGRES_DB: database
      PGDATA: /var/lib/postgresql/data/pgdata
    volumes:
      - ./postgresql.conf:/etc/postgresql/postgresql.conf
      - ./ssl-server:/var/lib/postgresql/data/
    ports:
      - '5432:5432'
    networks:
      - postgres-ssl

networks:
  postgres-ssl:
    name: postgres-ssl

最后,这是我的Python代码,尽管这里的一切都按预期工作,因为我得到了上面的错误:

from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String
from typing import List

app = FastAPI()

DATABASE_URL = "postgresql+psycopg2://username:password@postgres/database?sslmode=require"

engine = create_engine(DATABASE_URL)

SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)

Base = declarative_base()

def get_db():
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()


class Student(Base):
    __tablename__ = 'students'

    id = Column(Integer, primary_key=True, nullable=False)
    name = Column(String, nullable=False)

class StudentRequest(BaseModel):
    name: str

    class Config:
        orm_mode = True

class StudentCreate(BaseModel):
   name :str

@app.post("/items/", response_model=StudentRequest)
def create_item(item: StudentCreate):
    db = SessionLocal()
    db_item = Student(**item.dict())
    db.add(db_item)
    db.commit()
    db.refresh(db_item)
    db.close()
    return db_item

@app.get("/items/", response_model=List[StudentRequest])
def get_items():
    db = SessionLocal()
    items = db.query(Student).all()
    db.close()
    return items

@app.get("/")
async def read_root():
    return {"message": "Hello, FastAPI with PostgreSQL using SSL!"}

如果我尝试通过将其挂载到相同的PGDATA路径来“覆盖”默认配置文件,我会得到一个错误:

这是这种情况下的docker-compose:

version: '3.8'
services:
  app:
    container_name: python-app
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - '8000:80'
    depends_on:
      - postgres
    networks:
      - postgres-ssl

  postgres:
    container_name: postgres
    image: postgres:latest
    environment:
      POSTGRES_USER: username
      POSTGRES_PASSWORD: password
      POSTGRES_DB: database
      PGDATA: /etc/postgresql/data
    volumes:
      - ./postgresql.conf:/etc/postgresql/data/postgresql.conf
      - ./ssl-server:/etc/postgresql/data/ssl-server
    ports:
      - '5432:5432'
    networks:
      - postgres-ssl

networks:
  postgres-ssl:
    name: postgres-ssl

以及我在启动时收到的错误:

postgres  | The files belonging to this database system will be owned by user "postgres".
postgres  | This user must also own the server process.
postgres  | 
postgres  | 
postgres  | The database cluster will be initialized with locale "en_US.utf8".
postgres  | The default database encoding has accordingly been set to "UTF8".
postgres  | The default text search configuration will be set to "english".
postgres  | 
postgres  | Data page checksums are disabled.
postgres  | 
postgres  | 
postgres  | initdb: error: directory "/etc/postgresql/data" exists but is not empty
postgres  | initdb: hint: If you want to create a new database system, either remove or empty the directory "/etc/postgresql/data" or run initdb with an argument other than "/etc/postgresql/data".
postgres exited with code 1

我在这里漏掉了什么吗?为什么这不会设置SSL连接? :/

我非常困惑,如果你能在这里帮助我,我将非常非常感激!

提前谢谢你,祝你有美好的一天!

英文:

Hi PostgreSQL在SSL模式下返回”服务器不支持SSL,但需要SSL”的错误信息。 Hope you're doing great!

I a trying to enable SSL communications between a Postgres docker container and a FastAPI container, however as you can tell from the title, something is not working :/

I read the documentation and supposedly I have set up everything accordingly. For instance:

  1. I created the root CA, and then a key and signed cert for the postgres server with the root CA.

  2. I have configured the postgresql.conf file in this manner:

... defaults

# - SSL -

ssl = on
ssl_ca_file = '/var/lib/postgresql/data/root.crt'
ssl_cert_file = '/var/lib/postgresql/data/server.crt'
ssl_key_file = '/var/lib/postgresql/data/server.key'
#ssl_crl_file = ''
#ssl_crl_dir = ''
#ssl_ciphers = 'HIGH:MEDIUM:+3DES:!aNULL' # allowed SSL ciphers
#ssl_prefer_server_ciphers = on
#ssl_ecdh_curve = 'prime256v1'
#ssl_min_protocol_version = 'TLSv1.2'
#ssl_max_protocol_version = ''
#ssl_dh_params_file = ''
#ssl_passphrase_command = ''
#ssl_passphrase_command_supports_reload = off

... defaults

This is what my tree looks like:

.
├── docker-compose.yaml
├── Dockerfile
├── main.py
├── postgresql.conf
├── README.md
├── ssl-client
│   ├── root.crt
│   ├── root.csr
│   ├── root.key
│   ├── server.crt
│   ├── server.csr
│   └── server.key
└── ssl-server
    ├── pgdata  [error opening dir]   -> because it is using its own user (999)
    ├── root.crt
    ├── root.csr
    ├── root.key
    ├── server.crt
    ├── server.csr
    └── server.key

and this is how I am passing everything to the container:

version: '3.8'
services:
  app:
    container_name: python-app
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - '8000:80'
    depends_on:
      - postgres
    networks:
      - postgres-ssl

  postgres:
    container_name: postgres
    image: postgres:latest
    environment:
      POSTGRES_USER: username
      POSTGRES_PASSWORD: password
      POSTGRES_DB: database
      PGDATA: /var/lib/postgresql/data/pgdata
    volumes:
      - ./postgresql.conf:/etc/postgresql/postgresql.conf
      - ./ssl-server:/var/lib/postgresql/data/
    ports:
      - '5432:5432'
    networks:
      - postgres-ssl

networks:
  postgres-ssl:
    name: postgres-ssl

Lastly, here is my python code, although everything is working as expected here, as I am getting the error above:

from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String
from typing import List

app = FastAPI()

DATABASE_URL = "postgresql+psycopg2://username:password@postgres/database?sslmode=require"

engine = create_engine(DATABASE_URL)

SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)

Base = declarative_base()

def get_db():
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()


class Student(Base):
    __tablename__ = 'students'

    id = Column(Integer, primary_key=True, nullable=False)
    name = Column(String, nullable=False)

class StudentRequest(BaseModel):
    name: str

    class Config:
        orm_mode = True

class StudentCreate(BaseModel):
   name :str

@app.post("/items/", response_model=StudentRequest)
def create_item(item: StudentCreate):
    db = SessionLocal()
    db_item = Student(**item.dict())
    db.add(db_item)
    db.commit()
    db.refresh(db_item)
    db.close()
    return db_item

@app.get("/items/", response_model=List[StudentRequest])
def get_items():
    db = SessionLocal()
    items = db.query(Student).all()
    db.close()
    return items

@app.get("/")
async def read_root():
    return {"message": "Hello, FastAPI with PostgreSQL using SSL!"}

If I try to 'override' the default configuration file by mounting it in the same PGDATA path, I get an error:

Here is the docker-compose for this case:

version: '3.8'
services:
  app:
    container_name: python-app
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - '8000:80'
    depends_on:
      - postgres
    networks:
      - postgres-ssl

  postgres:
    container_name: postgres
    image: postgres:latest
    environment:
      POSTGRES_USER: username
      POSTGRES_PASSWORD: password
      POSTGRES_DB: database
      PGDATA: /etc/postgresql/data
    volumes:
      - ./postgresql.conf:/etc/postgresql/data/postgresql.conf
      - ./ssl-server:/etc/postgresql/data/ssl-server
    ports:
      - '5432:5432'
    networks:
      - postgres-ssl

networks:
  postgres-ssl:
    name: postgres-ssl

And the error I get at startup:

postgres  | The files belonging to this database system will be owned by user "postgres".
postgres  | This user must also own the server process.
postgres  | 
postgres  | 
postgres  | The database cluster will be initialized with locale "en_US.utf8".
postgres  | The default database encoding has accordingly been set to "UTF8".
postgres  | The default text search configuration will be set to "english".
postgres  | 
postgres  | Data page checksums are disabled.
postgres  | 
postgres  | 
postgres  | initdb: error: directory "/etc/postgresql/data" exists but is not empty
postgres  | initdb: hint: If you want to create a new database system, either remove or empty the directory "/etc/postgresql/data" or run initdb with an argument other than "/etc/postgresql/data".
postgres exited with code 1

Am I missing something here? How come this is not setting up SSL connections? :/

I am very confused honestly, if you could help me out here, it would be very, very much appreciated!

Thank you in advance and have a wonderful day!

答案1

得分: 1

如果PGDATA设置为/var/lib/postgresql/data/pgdata,那么将自定义配置文件放在/etc/postgresql/中是没有任何作用的。它只会忽略该文件并使用默认配置。

此外,证书和其他内容需要放在PGDATA目录内,而不是与其同级。

英文:

If PGDATA is set to /var/lib/postgresql/data/pgdata, then putting your custom config file in /etc/postgresql/ isn't going to do anything. It will just ignore it and use the default.

Furthermore, the certs and stuff need to be inside PGDATA, not siblings to it.

huangapple
  • 本文由 发表于 2023年8月9日 01:56:10
  • 转载请务必保留本文链接:https://go.coder-hub.com/76862093.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定